From aac1141ca6884bd4693127f800cc911c81c5d359 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 11 Feb 2018 06:05:41 -0500 Subject: [PATCH 001/115] fix issue #1107 --- libi2pd/HTTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 24e55457..9bca11d7 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -84,7 +84,7 @@ namespace http { pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */ if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) { std::size_t delim = url.find(':', pos_p); - if (delim != std::string::npos && delim < pos_c) { + if (delim && delim != std::string::npos && delim < pos_c) { user = url.substr(pos_p, delim - pos_p); delim += 1; pass = url.substr(delim, pos_c - delim); From 182ffe44954e76fe443e30b5d45509d9864a1192 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 9 Mar 2018 14:56:06 -0500 Subject: [PATCH 002/115] use croorect encryption type for tunnel build --- libi2pd/CryptoKey.cpp | 24 ++++++++++++------------ libi2pd/CryptoKey.h | 16 ++++++++-------- libi2pd/Destination.cpp | 2 +- libi2pd/I2NPProtocol.cpp | 2 +- libi2pd/LeaseSet.cpp | 2 +- libi2pd/RouterContext.cpp | 7 ++++++- libi2pd/RouterContext.h | 1 + libi2pd/RouterInfo.cpp | 2 +- libi2pd/TunnelConfig.h | 5 +++-- libi2pd_client/I2CP.cpp | 2 +- 10 files changed, 35 insertions(+), 28 deletions(-) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index cd6952a0..711d4ce6 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -12,9 +12,9 @@ namespace crypto memcpy (m_PublicKey, pub, 256); } - void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) { - ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, true); + ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding); } ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv) @@ -22,9 +22,9 @@ namespace crypto memcpy (m_PrivateKey, priv, 256); } - bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) { - return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, true); + return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding); } ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub) @@ -44,10 +44,10 @@ namespace crypto if (m_PublicKey) EC_POINT_free (m_PublicKey); } - void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) { if (m_Curve && m_PublicKey) - ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, true); + ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, zeroPadding); } ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv) @@ -62,10 +62,10 @@ namespace crypto if (m_PrivateKey) BN_free (m_PrivateKey); } - bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) { if (m_Curve && m_PrivateKey) - return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, true); + return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, zeroPadding); return false; } @@ -104,10 +104,10 @@ namespace crypto if (m_PublicKey) EC_POINT_free (m_PublicKey); } - void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) { if (m_PublicKey) - ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, true); + ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, zeroPadding); } ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv) @@ -120,10 +120,10 @@ namespace crypto if (m_PrivateKey) BN_free (m_PrivateKey); } - bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) { if (m_PrivateKey) - return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, true); + return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, zeroPadding); return false; } diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index ece86eb0..0dff7584 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -13,7 +13,7 @@ namespace crypto public: virtual ~CryptoKeyEncryptor () {}; - virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted + virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) = 0; // 222 bytes data, 512/514 bytes encrypted }; class CryptoKeyDecryptor @@ -21,7 +21,7 @@ namespace crypto public: virtual ~CryptoKeyDecryptor () {}; - virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) = 0; // 512 bytes encrypted, 222 bytes data + virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) = 0; // 512/514 bytes encrypted, 222 bytes data }; // ElGamal @@ -30,7 +30,7 @@ namespace crypto public: ElGamalEncryptor (const uint8_t * pub); - void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding); private: @@ -42,7 +42,7 @@ namespace crypto public: ElGamalDecryptor (const uint8_t * priv); - bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); private: @@ -57,7 +57,7 @@ namespace crypto ECIESP256Encryptor (const uint8_t * pub); ~ECIESP256Encryptor (); - void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding); private: @@ -72,7 +72,7 @@ namespace crypto ECIESP256Decryptor (const uint8_t * priv); ~ECIESP256Decryptor (); - bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); private: @@ -90,7 +90,7 @@ namespace crypto ECIESGOSTR3410Encryptor (const uint8_t * pub); ~ECIESGOSTR3410Encryptor (); - void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding); private: @@ -104,7 +104,7 @@ namespace crypto ECIESGOSTR3410Decryptor (const uint8_t * priv); ~ECIESGOSTR3410Decryptor (); - bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); private: diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b191cbf1..bafd49da 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1024,7 +1024,7 @@ namespace client bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const { if (m_Decryptor) - return m_Decryptor->Decrypt (encrypted, data, ctx); + return m_Decryptor->Decrypt (encrypted, data, ctx, true); else LogPrint (eLogError, "Destinations: decryptor is not set"); return false; diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 9bb7dfd1..c91bfdb3 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -327,7 +327,7 @@ namespace i2p { LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); + i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); BN_CTX_free (ctx); // replace record to reply if (i2p::context.AcceptsTunnels () && diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index f2355930..8b6063fc 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -212,7 +212,7 @@ namespace data { auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey); if (encryptor) - encryptor->Encrypt (data, encrypted, ctx); + encryptor->Encrypt (data, encrypted, ctx, true); } LocalLeaseSet::LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels): diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 38fe3224..99f79df6 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -482,6 +482,11 @@ namespace i2p bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const { - return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx) : false; + return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false; + } + + bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const + { + return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false; } } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ef23af25..4bd324f5 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -61,6 +61,7 @@ namespace i2p void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; + bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index e9c2a384..e3f4d2d4 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -840,7 +840,7 @@ namespace data { auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr); if (encryptor) - encryptor->Encrypt (data, encrypted, ctx); + encryptor->Encrypt (data, encrypted, ctx, true); } } } diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 9707fa17..48e66f2e 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -5,7 +5,6 @@ #include #include #include -#include "Crypto.h" #include "Identity.h" #include "RouterContext.h" #include "Timestamp.h" @@ -103,7 +102,9 @@ namespace tunnel htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ()); htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID); RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET); - i2p::crypto::ElGamalEncrypt (ident->GetEncryptionPublicKey (), clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx); + auto encryptor = ident->CreateEncryptor (nullptr); + if (encryptor) + encryptor->Encrypt (clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx, false); memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); } }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 361d9f94..b08fded1 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -37,7 +37,7 @@ namespace client bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const { if (m_Decryptor) - return m_Decryptor->Decrypt (encrypted, data, ctx); + return m_Decryptor->Decrypt (encrypted, data, ctx, true); else LogPrint (eLogError, "I2CP: decryptor is not set"); return false; From ce8d701ecb92be1563681ec9ce98a9e4d02041fd Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 11 Mar 2018 19:20:47 +0300 Subject: [PATCH 003/115] WITH_LIBRARY usage closes #1146. Need to be checked before. --- build/CMakeLists.txt | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 364c3304..fc9ca417 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -94,14 +94,17 @@ endif() add_library(libi2pd ${LIBI2PD_SRC}) set_target_properties(libi2pd PROPERTIES PREFIX "") -install(TARGETS libi2pd - EXPORT libi2pd - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - COMPONENT Libraries) + +if (WITH_LIBRARY) + install(TARGETS libi2pd + EXPORT libi2pd + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT Libraries) # TODO Make libi2pd available to 3rd party projects via CMake as imported target # FIXME This pulls stdafx # install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() set (CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp" @@ -120,13 +123,17 @@ set (CLIENT_SRC if(WITH_WEBSOCKETS) list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp") endif () + add_library(libi2pdclient ${CLIENT_SRC}) set_target_properties(libi2pdclient PROPERTIES PREFIX "") -install(TARGETS libi2pdclient - EXPORT libi2pdclient - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - COMPONENT Libraries) + +if (WITH_LIBRARY) + install(TARGETS libi2pdclient + EXPORT libi2pdclient + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT Libraries) +endif() set(DAEMON_SRC_DIR ../daemon) From b1a6c5ddf7787b4275ec77730f59fa1324159d6c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 16 Mar 2018 11:12:18 -0400 Subject: [PATCH 004/115] fixed build for gcc 4.7 --- libi2pd/NTCPSession.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index e3d6c004..e0bd1135 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -178,7 +178,8 @@ namespace transport } // TODO: check for number of pending keys auto s = shared_from_this (); - m_Server.Work(s, [s]() -> std::function { + // TODO: we need to pass this for gcc 4.7, should be removed later on + m_Server.Work(s, [s, this]() -> std::function { if (!s->m_DHKeysPair) s->m_DHKeysPair = transports.GetNextDHKeysPair (); s->CreateAESKey (s->m_Establisher->phase1.pubKey); @@ -242,7 +243,8 @@ namespace transport else { auto s = shared_from_this (); - m_Server.Work(s, [s]() -> std::function { + // TODO: we need to pass this for gcc 4.7, should be removed later on + m_Server.Work(s, [s, this]() -> std::function { s->CreateAESKey (s->m_Establisher->phase2.pubKey); return std::bind(&NTCPSession::HandlePhase2, s); }); From b7c350202d63e7413bc4b21d61426fe6d5229340 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 20 Mar 2018 20:43:47 -0400 Subject: [PATCH 005/115] always create EdDSA RouterInfo --- libi2pd/RouterContext.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 99f79df6..a82ace85 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -34,11 +34,7 @@ namespace i2p void RouterContext::CreateNewRouter () { -#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); -#else - m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); -#endif SaveKeys (); NewRouterInfo (); } From b041bcdc655c45fa106392cd272f8eddcb867326 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 23 Mar 2018 11:41:36 -0400 Subject: [PATCH 006/115] publish updated LeaseSet in destination's thread --- libi2pd/Destination.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index bafd49da..b7c2ee32 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -281,8 +281,12 @@ namespace client i2p::garlic::GarlicDestination::SetLeaseSetUpdated (); if (m_IsPublic) { - m_PublishVerificationTimer.cancel (); - Publish (); + auto s = shared_from_this (); + m_Service.post ([s](void) + { + s->m_PublishVerificationTimer.cancel (); + s->Publish (); + }); } } From 5361e11395114c4d6ccdb4489866364d906cc74a Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 20 Mar 2018 15:14:31 -0400 Subject: [PATCH 007/115] fix race --- libi2pd/NTCPSession.cpp | 33 +++++++++++++++++++++------------ libi2pd/NTCPSession.h | 6 ++++-- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index e3d6c004..de4306e6 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -24,6 +24,12 @@ namespace i2p { namespace transport { + + struct NTCPWork + { + std::shared_ptr session; + }; + NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), @@ -177,18 +183,20 @@ namespace transport } } // TODO: check for number of pending keys - auto s = shared_from_this (); - m_Server.Work(s, [s]() -> std::function { - if (!s->m_DHKeysPair) - s->m_DHKeysPair = transports.GetNextDHKeysPair (); - s->CreateAESKey (s->m_Establisher->phase1.pubKey); - return std::bind(&NTCPSession::SendPhase2, s); + auto work = new NTCPWork{shared_from_this()}; + m_Server.Work(work->session, [work]() -> std::function { + if (!work->session->m_DHKeysPair) + work->session->m_DHKeysPair = transports.GetNextDHKeysPair (); + work->session->CreateAESKey (work->session->m_Establisher->phase1.pubKey); + return std::bind(&NTCPSession::SendPhase2, work->session, work); }); } } - void NTCPSession::SendPhase2 () + void NTCPSession::SendPhase2 (NTCPWork * work) { + if(work) + delete work; const uint8_t * y = m_DHKeysPair->GetPublicKey (); memcpy (m_Establisher->phase2.pubKey, y, 256); uint8_t xy[512]; @@ -241,16 +249,17 @@ namespace transport } else { - auto s = shared_from_this (); - m_Server.Work(s, [s]() -> std::function { - s->CreateAESKey (s->m_Establisher->phase2.pubKey); - return std::bind(&NTCPSession::HandlePhase2, s); + auto work = new NTCPWork{shared_from_this()}; + m_Server.Work(work->session, [work]() -> std::function { + work->session->CreateAESKey (work->session->m_Establisher->phase2.pubKey); + return std::bind(&NTCPSession::HandlePhase2, work->session, work); }); } } - void NTCPSession::HandlePhase2 () + void NTCPSession::HandlePhase2 (NTCPWork * work) { + if(work) delete work; m_Decryption.SetIV (m_Establisher->phase2.pubKey + 240); m_Encryption.SetIV (m_Establisher->phase1.HXxorHI + 16); diff --git a/libi2pd/NTCPSession.h b/libi2pd/NTCPSession.h index 5335fbdd..e2207eb7 100644 --- a/libi2pd/NTCPSession.h +++ b/libi2pd/NTCPSession.h @@ -35,6 +35,8 @@ namespace transport } encrypted; }; + struct NTCPWork; + const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds @@ -77,12 +79,12 @@ namespace transport void SendPhase3 (); void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void HandlePhase2 (); + void HandlePhase2 (NTCPWork * work=nullptr); void HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA); void HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA); //server - void SendPhase2 (); + void SendPhase2 (NTCPWork * work=nullptr); void SendPhase4 (uint32_t tsA, uint32_t tsB); void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB); From f11266972e81a6db65aeecc3f77fe2b47418385c Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Fri, 30 Mar 2018 15:50:30 +0300 Subject: [PATCH 008/115] Change jni to build executable. Clone with minimal changes DaemonUnix into DaemonAndroid --- android/jni/Android.mk | 8 +- android/jni/Application.mk | 8 +- android/jni/DaemonAndroid.cpp | 356 +++++++++++----------- android/jni/DaemonAndroid.h | 113 +++---- android/jni/i2pd_android.cpp | 66 ---- android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 33 -- 6 files changed, 230 insertions(+), 354 deletions(-) delete mode 100755 android/jni/i2pd_android.cpp delete mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index d5a8f05f..90284995 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -12,15 +12,15 @@ LOCAL_STATIC_LIBRARIES := \ miniupnpc LOCAL_LDLIBS := -lz -LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \ +LOCAL_SRC_FILES := DaemonAndroid.cpp $(IFADDRS_PATH)/ifaddrs.c \ $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/Daemon.cpp \ $(DAEMON_SRC_PATH)/UPnP.cpp \ $(DAEMON_SRC_PATH)/HTTPServer.cpp \ - $(DAEMON_SRC_PATH)/I2PControl.cpp - -include $(BUILD_SHARED_LIBRARY) + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/i2pd.cpp +include $(BUILD_EXECUTABLE) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0fa116c2..acc6f895 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,12 +9,14 @@ APP_PLATFORM := android-14 # http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse NDK_TOOLCHAIN_VERSION := 4.9 # APP_STL := stlport_shared --> does not seem to contain C++11 features -APP_STL := gnustl_shared +#APP_STL := gnustl_shared +APP_STL := gnustl_static # Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 +APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif @@ -26,7 +28,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /path/to/libraries +I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..94c679be 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,193 +1,193 @@ #include "DaemonAndroid.h" -#include "Daemon.h" -#include -#include -#include -#include -//#include "mainwindow.h" + +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include + +#include "Config.h" +#include "FS.h" +#include "Log.h" +#include "Tunnel.h" +#include "RouterContext.h" +#include "ClientContext.h" + +void handle_signal(int sig) +{ + switch (sig) + { + case SIGHUP: + LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration..."); + i2p::client::context.ReloadConfig(); + break; + case SIGUSR1: + LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs..."); + i2p::log::Logger().Reopen (); + break; + case SIGINT: + if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) + { + i2p::context.SetAcceptsTunnels (false); + Daemon.gracefulShutdownInterval = 10*60; // 10 minutes + LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); + } + else + Daemon.running = 0; + break; + case SIGABRT: + case SIGTERM: + Daemon.running = 0; // Exit loop + break; + case SIGPIPE: + LogPrint(eLogInfo, "SIGPIPE received"); + break; + } +} namespace i2p { -namespace android -{ -/* Worker::Worker (DaemonAndroidImpl& daemon): - m_Daemon (daemon) + namespace util { - } - - void Worker::startDaemon() - { - Log.d(TAG"Performing daemon start..."); - m_Daemon.start(); - Log.d(TAG"Daemon started."); - emit resultReady(); - } - void Worker::restartDaemon() - { - Log.d(TAG"Performing daemon restart..."); - m_Daemon.restart(); - Log.d(TAG"Daemon restarted."); - emit resultReady(); - } - void Worker::stopDaemon() { - Log.d(TAG"Performing daemon stop..."); - m_Daemon.stop(); - Log.d(TAG"Daemon stopped."); - emit resultReady(); - } - - Controller::Controller(DaemonAndroidImpl& daemon): - m_Daemon (daemon) - { - Worker *worker = new Worker (m_Daemon); - worker->moveToThread(&workerThread); - connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); - connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); - connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); - connect(worker, &Worker::resultReady, this, &Controller::handleResults); - workerThread.start(); - } - Controller::~Controller() - { - Log.d(TAG"Closing and waiting for daemon worker thread..."); - workerThread.quit(); - workerThread.wait(); - Log.d(TAG"Waiting for daemon worker thread finished."); - if(m_Daemon.isRunning()) - { - Log.d(TAG"Stopping the daemon..."); - m_Daemon.stop(); - Log.d(TAG"Stopped the daemon."); - } - } -*/ - DaemonAndroidImpl::DaemonAndroidImpl () - //: - /*mutex(nullptr), */ - //m_IsRunning(false), - //m_RunningChangedCallback(nullptr) - { - } - - DaemonAndroidImpl::~DaemonAndroidImpl () - { - //delete mutex; - } - - bool DaemonAndroidImpl::init(int argc, char* argv[]) - { - //mutex=new QMutex(QMutex::Recursive); - //setRunningCallback(0); - //m_IsRunning=false; - return Daemon.init(argc,argv); - } - - void DaemonAndroidImpl::start() - { - //QMutexLocker locker(mutex); - //setRunning(true); - Daemon.start(); - } - - void DaemonAndroidImpl::stop() - { - //QMutexLocker locker(mutex); - Daemon.stop(); - //setRunning(false); - } - - void DaemonAndroidImpl::restart() - { - //QMutexLocker locker(mutex); - stop(); - start(); - } - /* - void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) - { - m_RunningChangedCallback = cb; - } - - bool DaemonAndroidImpl::isRunning() - { - return m_IsRunning; - } - - void DaemonAndroidImpl::setRunning(bool newValue) - { - bool oldValue = m_IsRunning; - if(oldValue!=newValue) + bool DaemonAndroid::start() { - m_IsRunning = newValue; - if(m_RunningChangedCallback) - m_RunningChangedCallback(); - } - } -*/ - static DaemonAndroidImpl daemon; - static char* argv[1]={strdup("tmp")}; - /** - * returns error details if failed - * returns "ok" if daemon initialized and started okay - */ - std::string start(/*int argc, char* argv[]*/) - { - try - { - //int result; - + if (isDaemon) { - //Log.d(TAG"Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(1,argv); - if(!daemonInitSuccess) - { - //QMessageBox::critical(0, "Error", "Daemon init failed"); - return "Daemon init failed"; - } - //Log.d(TAG"Initialised, creating the main window..."); - //MainWindow w; - //Log.d(TAG"Before main window.show()..."); - //w.show (); + pid_t pid; + pid = fork(); + if (pid > 0) // parent + ::exit (EXIT_SUCCESS); + if (pid < 0) // error { - //i2p::qt::Controller daemonQtController(daemon); - //Log.d(TAG"Starting the daemon..."); - //emit daemonQtController.startDaemon(); - //daemon.start (); - //Log.d(TAG"Starting GUI event loop..."); - //result = app.exec(); - //daemon.stop (); - daemon.start(); + LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); + return false; + } + + // child + umask(S_IWGRP | S_IRWXO); // 0027 + int sid = setsid(); + if (sid < 0) + { + LogPrint(eLogError, "Daemon: could not create process group."); + return false; + } + std::string d = i2p::fs::GetDataDir(); + if (chdir(d.c_str()) != 0) + { + LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); + return false; + } + + // point std{in,out,err} descriptors to /dev/null + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + } + + // set proc limits + struct rlimit limit; + uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); + getrlimit(RLIMIT_NOFILE, &limit); + if (nfiles == 0) { + LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); + } else if (nfiles <= limit.rlim_max) { + limit.rlim_cur = nfiles; + if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { + LogPrint(eLogInfo, "Daemon: set max number of open files to ", + nfiles, " (system limit is ", limit.rlim_max, ")"); + } else { + LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); + } + } else { + LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); + } + uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); + if (cfsize) // core file size set + { + cfsize *= 1024; + getrlimit(RLIMIT_CORE, &limit); + if (cfsize <= limit.rlim_max) { + limit.rlim_cur = cfsize; + if (setrlimit(RLIMIT_CORE, &limit) != 0) { + LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); + } else if (cfsize == 0) { + LogPrint(eLogInfo, "Daemon: coredumps disabled"); + } else { + LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); + } + } else { + LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); } } - //QMessageBox::information(&w, "Debug", "demon stopped"); - //Log.d(TAG"Exiting the application"); - //return result; - } - catch (boost::exception& ex) - { - std::stringstream ss; - ss << boost::diagnostic_information(ex); - return ss.str(); - } - catch (std::exception& ex) - { - std::stringstream ss; - ss << ex.what(); - return ss.str(); - } - catch(...) - { - return "unknown exception"; - } - return "ok"; - } + // Pidfile + // this code is c-styled and a bit ugly + std::string pidfile; i2p::config::GetOption("pidfile", pidfile); + if (pidfile == "") { + pidfile = i2p::fs::DataDirPath("i2pd.pid"); + } + if (pidfile != "") { + pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); + if (pidFH < 0) + { + LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); + return false; + } + char pid[10]; + sprintf(pid, "%d\n", getpid()); + ftruncate(pidFH, 0); + if (write(pidFH, pid, strlen(pid)) < 0) + { + LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); + return false; + } + } + gracefulShutdownInterval = 0; // not specified - void stop() - { - daemon.stop(); + // Signal handler + struct sigaction sa; + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + + return Daemon_Singleton::start(); + } + + bool DaemonAndroid::stop() + { + i2p::fs::Remove(pidfile); + + return Daemon_Singleton::stop(); + } + + void DaemonAndroid::run () + { + while (running) + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + if (gracefulShutdownInterval) + { + gracefulShutdownInterval--; // - 1 second + if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0) + { + LogPrint(eLogInfo, "Graceful shutdown"); + return; + } + } + } + } } } -} + +#endif diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index 9cc8219b..c62d7c76 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -1,87 +1,60 @@ -#ifndef DAEMON_ANDROID_H -#define DAEMON_ANDROID_H +#ifndef DAEMON_H__ +#define DAEMON_H__ +#include #include namespace i2p { -namespace android +namespace util { - class DaemonAndroidImpl - { - public: + class Daemon_Singleton_Private; + class Daemon_Singleton + { + public: + virtual bool init(int argc, char* argv[]); + virtual bool start(); + virtual bool stop(); + virtual void run () {}; - DaemonAndroidImpl (); - ~DaemonAndroidImpl (); + bool isDaemon; + bool running; - //typedef void (*runningChangedCallback)(); + protected: + Daemon_Singleton(); + virtual ~Daemon_Singleton(); - /** - * @return success - */ - bool init(int argc, char* argv[]); - void start(); - void stop(); - void restart(); - //void setRunningCallback(runningChangedCallback cb); - //bool isRunning(); - private: - //void setRunning(bool running); - private: - //QMutex* mutex; - //bool m_IsRunning; - //runningChangedCallback m_RunningChangedCallback; - }; + bool IsService () const; - /** - * returns "ok" if daemon init failed - * returns errinfo if daemon initialized and started okay - */ - std::string start(); + // d-pointer for httpServer, httpProxy, etc. + class Daemon_Singleton_Private; + Daemon_Singleton_Private &d; + }; - // stops the daemon - void stop(); +#if defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + class DaemonAndroid : public Daemon_Singleton + { + public: + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } - /* - class Worker : public QObject - { - Q_OBJECT - public: + bool start(); + bool stop(); + void run (); - Worker (DaemonAndroidImpl& daemon); + private: + std::string pidfile; + int pidFH; - private: - - DaemonAndroidImpl& m_Daemon; - - public slots: - void startDaemon(); - void restartDaemon(); - void stopDaemon(); - - signals: - void resultReady(); - }; - - class Controller : public QObject - { - Q_OBJECT - QThread workerThread; - public: - Controller(DaemonAndroidImpl& daemon); - ~Controller(); - private: - DaemonAndroidImpl& m_Daemon; - - public slots: - void handleResults(){} - signals: - void startDaemon(); - void stopDaemon(); - void restartDaemon(); - }; - */ + public: + int gracefulShutdownInterval; // in seconds + }; +#endif } } -#endif // DAEMON_ANDROID_H +#endif // DAEMON_H__ diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp deleted file mode 100755 index 8791c90b..00000000 --- a/android/jni/i2pd_android.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -//#include -#include -#include "org_purplei2p_i2pd_I2PD_JNI.h" -#include "DaemonAndroid.h" -#include "RouterContext.h" -#include "Transports.h" - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv * env, jclass clazz) { -#if defined(__arm__) - #if defined(__ARM_ARCH_7A__) - #if defined(__ARM_NEON__) - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a/NEON (hard-float)" - #else - #define ABI "armeabi-v7a/NEON" - #endif - #else - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a (hard-float)" - #else - #define ABI "armeabi-v7a" - #endif - #endif - #else - #define ABI "armeabi" - #endif -#elif defined(__i386__) - #define ABI "x86" -#elif defined(__x86_64__) - #define ABI "x86_64" -#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ - #define ABI "mips64" -#elif defined(__mips__) - #define ABI "mips" -#elif defined(__aarch64__) - #define ABI "arm64-v8a" -#else - #define ABI "unknown" -#endif - - return env->NewStringUTF(ABI); -} - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv * env, jclass clazz) { - return env->NewStringUTF(i2p::android::start().c_str()); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv * env, jclass clazz) { - i2p::android::stop(); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv * env, jclass clazz) { - i2p::context.SetAcceptsTunnels (false); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected) -{ - bool isConnectedBool = (bool) isConnected; - i2p::transport::transports.SetOnline (isConnectedBool); -} diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h deleted file mode 100644 index 04923d22..00000000 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ /dev/null @@ -1,33 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class org_purplei2p_i2pd_I2PD_JNI */ - -#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI -#define _Included_org_purplei2p_i2pd_I2PD_JNI -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_purplei2p_i2pd_I2PD_JNI - * Method: stringFromJNI - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv *, jclass); - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected); - -#ifdef __cplusplus -} -#endif -#endif From f06c8710be43440526c487400aa5c681d30172ad Mon Sep 17 00:00:00 2001 From: yangfl Date: Sat, 31 Mar 2018 14:56:45 +0800 Subject: [PATCH 009/115] fix systemd service type --- contrib/i2pd.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.service b/contrib/i2pd.service index 9af96c37..ecfb4e20 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -10,7 +10,7 @@ RuntimeDirectory=i2pd RuntimeDirectoryMode=0700 LogsDirectory=i2pd LogsDirectoryMode=0700 -Type=simple +Type=fork ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service ExecReload=/bin/kill -HUP $MAINPID PIDFile=/var/run/i2pd/i2pd.pid From c0436297c2e8f4d3fad2b7658b99b81c150a74df Mon Sep 17 00:00:00 2001 From: yangfl Date: Sun, 1 Apr 2018 22:57:51 +0800 Subject: [PATCH 010/115] fix typo in systemd service type --- contrib/i2pd.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/i2pd.service b/contrib/i2pd.service index ecfb4e20..3f53bfb8 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -10,7 +10,7 @@ RuntimeDirectory=i2pd RuntimeDirectoryMode=0700 LogsDirectory=i2pd LogsDirectoryMode=0700 -Type=fork +Type=forking ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service ExecReload=/bin/kill -HUP $MAINPID PIDFile=/var/run/i2pd/i2pd.pid From e80da3cbeba3fd37c25637409b93e9c00dc3fcbf Mon Sep 17 00:00:00 2001 From: Hypnosis-mewmew Date: Thu, 5 Apr 2018 15:40:44 +0800 Subject: [PATCH 011/115] fixes for i2pd_qt MSYS2 mingw32 --- libi2pd/RouterContext.h | 5 +++++ libi2pd/RouterInfo.h | 5 +++++ qt/i2pd_qt/i2pd_qt.pro | 10 ++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 4bd324f5..9f42b1e0 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -1,6 +1,11 @@ #ifndef ROUTER_CONTEXT_H__ #define ROUTER_CONTEXT_H__ +// i2pd_qt.pro defines this on Windows +#ifdef WINDOWS +#include +#endif + #include #include #include diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 09e2c015..09db6ee8 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -1,6 +1,11 @@ #ifndef ROUTER_INFO_H__ #define ROUTER_INFO_H__ +// i2pd_qt.pro defines this on Windows +#ifdef WINDOWS +#include +#endif + #include #include #include diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index a2ba4261..941dfff3 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -268,8 +268,14 @@ android { } linux:!android { - message("Using Linux settings") - LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc + message("Using Linux settings") + LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc +} + +windows:!android { + message("Using Windows settings") + DEFINES += BOOST_USE_WINDOWS_H WINDOWS + LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc } !android:!symbian:!maemo5:!simulator { From f4056e57bb37aee6609aafafd5d33b752e19afb2 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Apr 2018 07:16:41 -0400 Subject: [PATCH 012/115] rollback --- libi2pd/RouterContext.h | 5 ----- libi2pd/RouterInfo.h | 5 ----- 2 files changed, 10 deletions(-) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 9f42b1e0..4bd324f5 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -1,11 +1,6 @@ #ifndef ROUTER_CONTEXT_H__ #define ROUTER_CONTEXT_H__ -// i2pd_qt.pro defines this on Windows -#ifdef WINDOWS -#include -#endif - #include #include #include diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 09db6ee8..09e2c015 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -1,11 +1,6 @@ #ifndef ROUTER_INFO_H__ #define ROUTER_INFO_H__ -// i2pd_qt.pro defines this on Windows -#ifdef WINDOWS -#include -#endif - #include #include #include From 2cb6283d004b37c145cfd08e8a1a1521651e7868 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 6 Apr 2018 15:23:56 -0400 Subject: [PATCH 013/115] outproxy authorization --- libi2pd/Base.cpp | 15 +++++++++++++++ libi2pd/Base.h | 9 ++++++--- libi2pd_client/HTTPProxy.cpp | 18 +++++++++++++++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index 09f04c05..f80f2751 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -210,6 +210,21 @@ namespace data return 4*d.quot; } + std::string ToBase64Standard (const std::string& in) + { + auto len = Base64EncodingBufferSize (in.length ()); + char * str = new char[len+1]; + auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len); + str[l] = 0; + // replace '-' by '+' and '~' by '/' + for (size_t i = 0; i < l; i++) + if (str[i] == '-') str[i] = '+'; + else if (str[i] == '~') str[i] = '/'; + std::string s(str); + delete[] str; + return s; + } + /* * * iT64 diff --git a/libi2pd/Base.h b/libi2pd/Base.h index bc92376f..a273f468 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -15,10 +15,13 @@ namespace data { size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); - /** + /** Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes - */ - size_t Base64EncodingBufferSize(const size_t input_size); + */ + size_t Base64EncodingBufferSize(const size_t input_size); + + std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization + } // data } // i2p diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index ac5d907d..47f756d3 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -389,11 +389,19 @@ namespace proxy { m_ClientRequestURL.host = ""; m_ClientRequest.uri = m_ClientRequestURL.to_string(); + if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) + { + // http proxy authorization + std::string s = "basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); + m_ClientRequest.AddHeader("Proxy-Authorization", s); + } + m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); // assume http if empty schema - if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") { + if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") + { // handle upstream http proxy if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) @@ -409,14 +417,18 @@ namespace proxy { m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1)); })); } - } else if (m_ProxyURL.schema == "socks") { + } + else if (m_ProxyURL.schema == "socks") + { // handle upstream socks proxy if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port)); m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) { m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamSocksProxyConnect, this, std::placeholders::_1)); })); - } else { + } + else + { // unknown type, complain GenericProxyError("unknown outproxy url", m_ProxyURL.to_string().c_str()); } From ff4e254618a2724a23f316c1ad8c5257640cadc5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Apr 2018 10:30:13 -0400 Subject: [PATCH 014/115] 0.9.34 --- libi2pd/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/version.h b/libi2pd/version.h index 36e7eb6e..e0443415 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 33 +#define I2P_VERSION_MICRO 34 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From 82534eef1216510eea7e4e5ede9c27d2099953f0 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 11 Apr 2018 20:58:21 +0300 Subject: [PATCH 015/115] try fix appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f663c86a..68b74529 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - MSYSTEM: MINGW32 install: -- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc catgets" +- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu " - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" From 855cc9ed83b0cfb8a6efb844dc872d9a876cbbac Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Apr 2018 19:10:21 -0400 Subject: [PATCH 016/115] correct Proxy-Authroization --- libi2pd_client/HTTPProxy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 47f756d3..ffabb61d 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -282,6 +282,7 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { + m_ClientRequest.RemoveHeader("Proxy-"); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -392,7 +393,7 @@ namespace proxy { if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) { // http proxy authorization - std::string s = "basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); + std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); m_ClientRequest.AddHeader("Proxy-Authorization", s); } From 387e030d83cabee89913386271534d1d1259a881 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Apr 2018 21:25:20 -0400 Subject: [PATCH 017/115] correct cleanup for CONNECT --- libi2pd_client/HTTPProxy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index ffabb61d..2778f24a 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -219,7 +219,7 @@ namespace proxy { /* replace headers */ req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); /* add headers */ - req.AddHeader("Connection", "close"); /* keep-alive conns not supported yet */ + req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */ } /** @@ -282,7 +282,7 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { - m_ClientRequest.RemoveHeader("Proxy-"); + SanitizeHTTPRequest (m_ClientRequest); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -399,7 +399,7 @@ namespace proxy { m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); - + // assume http if empty schema if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") { From a9b64893d83bffbe8e908e0932b6eab560b40811 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 12:47:53 -0400 Subject: [PATCH 018/115] replace Proxy-Authorization --- libi2pd_client/HTTPProxy.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 2778f24a..5f00ffdb 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -282,7 +282,6 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { - SanitizeHTTPRequest (m_ClientRequest); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -392,7 +391,9 @@ namespace proxy { if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) { - // http proxy authorization + // remove existing authorization if any + m_ClientRequest.RemoveHeader("Proxy-"); + // add own http proxy authorization std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); m_ClientRequest.AddHeader("Proxy-Authorization", s); } From 48099a367e3fd967623f042d8f33d791e046cb09 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 15:13:50 -0400 Subject: [PATCH 019/115] send correct buffer to outproxy --- libi2pd_client/HTTPProxy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 5f00ffdb..805b3247 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -408,7 +408,7 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { - m_send_buf = m_recv_buf; + m_send_buf = m_ClientRequestBuffer.str (); GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port); } From 17aa91803a0019dd2a557956ff044bcf729434f5 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 15:40:25 -0400 Subject: [PATCH 020/115] update outproxy header in right place --- libi2pd_client/HTTPProxy.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 805b3247..69cda97f 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -389,15 +389,6 @@ namespace proxy { m_ClientRequestURL.host = ""; m_ClientRequest.uri = m_ClientRequestURL.to_string(); - if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) - { - // remove existing authorization if any - m_ClientRequest.RemoveHeader("Proxy-"); - // add own http proxy authorization - std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); - m_ClientRequest.AddHeader("Proxy-Authorization", s); - } - m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); @@ -408,7 +399,17 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { - m_send_buf = m_ClientRequestBuffer.str (); + if (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ()) + { + // remove existing authorization if any + m_ClientRequest.RemoveHeader("Proxy-"); + // add own http proxy authorization + std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); + m_ClientRequest.AddHeader("Proxy-Authorization", s); + } + m_send_buf = m_ClientRequest.to_string(); + m_recv_buf.erase(0, m_req_len); + m_send_buf.append(m_recv_buf); GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port); } From c175dc30f8b0fd4365f77e310eedbc44e2abcca9 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 16:29:49 -0400 Subject: [PATCH 021/115] correct uri for outproxy --- libi2pd_client/HTTPProxy.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 69cda97f..ea95a6bd 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -387,6 +387,7 @@ namespace proxy { LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host); m_ClientRequestURL.schema = ""; m_ClientRequestURL.host = ""; + std::string origURI = m_ClientRequest.uri; // TODO: what do we need to chage uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); m_ClientRequest.write(m_ClientRequestBuffer); @@ -399,6 +400,7 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { + m_ClientRequest.uri = origURI; if (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ()) { // remove existing authorization if any From 83932a6f0272a29e0128a77562f0543492221e75 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 16 Apr 2018 09:38:32 -0400 Subject: [PATCH 022/115] remove streaming bans --- libi2pd/Streaming.cpp | 76 +------------------------------- libi2pd/Streaming.h | 31 ------------- libi2pd_client/ClientContext.cpp | 4 +- libi2pd_client/I2PTunnel.h | 2 - 4 files changed, 3 insertions(+), 110 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 91acc9d0..afcda9ec 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -904,10 +904,7 @@ namespace stream m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_LastIncomingReceiveStreamID (0), m_PendingIncomingTimer (m_Owner->GetService ()), - m_ConnTrackTimer(m_Owner->GetService()), - m_ConnsPerMinute(DEFAULT_MAX_CONNS_PER_MIN), - m_LastBanClear(i2p::util::GetMillisecondsSinceEpoch()), - m_EnableDrop(false) + m_ConnTrackTimer(m_Owner->GetService()) { } @@ -923,7 +920,6 @@ namespace stream void StreamingDestination::Start () { - ScheduleConnTrack(); } void StreamingDestination::Stop () @@ -971,17 +967,7 @@ namespace stream auto incomingStream = CreateNewIncomingStream (); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); - if(ident && m_EnableDrop) - { - auto ih = ident->GetIdentHash(); - if(DropNewStream(ih)) - { - // drop - LogPrint(eLogWarning, "Streaming: Dropping connection, too many inbound streams from ", ih.ToBase32()); - incomingStream->Terminate(); - return; - } - } + m_LastIncomingReceiveStreamID = receiveStreamID; // handle saved packets if any @@ -1176,63 +1162,5 @@ namespace stream return msg; } - void StreamingDestination::SetMaxConnsPerMinute(const uint32_t conns) - { - m_EnableDrop = conns > 0; - m_ConnsPerMinute = conns; - LogPrint(eLogDebug, "Streaming: Set max conns per minute per destination to ", conns); - } - - bool StreamingDestination::DropNewStream(const i2p::data::IdentHash & ih) - { - std::lock_guard lock(m_ConnsMutex); - if (m_Banned.size() > MAX_BANNED_CONNS) return true; // overload - auto end = std::end(m_Banned); - if ( std::find(std::begin(m_Banned), end, ih) != end) return true; // already banned - auto itr = m_Conns.find(ih); - if (itr == m_Conns.end()) - m_Conns[ih] = 0; - - m_Conns[ih] += 1; - - bool ban = m_Conns[ih] >= m_ConnsPerMinute; - if (ban) - { - m_Banned.push_back(ih); - m_Conns.erase(ih); - LogPrint(eLogWarning, "Streaming: ban ", ih.ToBase32()); - } - return ban; - } - - void StreamingDestination::HandleConnTrack(const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - { // acquire lock - std::lock_guard lock(m_ConnsMutex); - // clear conn tracking - m_Conns.clear(); - // check for ban clear - auto ts = i2p::util::GetMillisecondsSinceEpoch(); - if (ts - m_LastBanClear >= DEFAULT_BAN_INTERVAL) - { - // clear bans - m_Banned.clear(); - m_LastBanClear = ts; - } - } - // reschedule timer - ScheduleConnTrack(); - } - } - - void StreamingDestination::ScheduleConnTrack() - { - m_ConnTrackTimer.expires_from_now (boost::posix_time::seconds(60)); - m_ConnTrackTimer.async_wait ( - std::bind (&StreamingDestination::HandleConnTrack, - shared_from_this (), std::placeholders::_1)); - } } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a114844d..9ce7e210 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -53,22 +53,6 @@ namespace stream const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 30; // in seconds - /** i2cp option for limiting inbound stremaing connections */ - const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns"; - /** default maximum connections attempts per minute per destination */ - const uint32_t DEFAULT_MAX_CONNS_PER_MIN = 600; - - /** - * max banned destinations per local destination - * TODO: make configurable - */ - const uint16_t MAX_BANNED_CONNS = 9999; - /** - * length of a ban in ms - * TODO: make configurable - */ - const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000; - struct Packet { size_t len, offset; @@ -273,9 +257,6 @@ namespace stream void HandleDataMessagePayload (const uint8_t * buf, size_t len); std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort); - /** set max connections per minute per destination */ - void SetMaxConnsPerMinute(const uint32_t conns); - Packet * NewPacket () { return m_PacketsPool.Acquire(); } void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); } @@ -286,13 +267,6 @@ namespace stream std::shared_ptr CreateNewIncomingStream (); void HandlePendingIncomingTimer (const boost::system::error_code& ecode); - /** handle cleaning up connection tracking for ratelimits */ - void HandleConnTrack(const boost::system::error_code& ecode); - - bool DropNewStream(const i2p::data::IdentHash & ident); - - void ScheduleConnTrack(); - private: std::shared_ptr m_Owner; @@ -310,13 +284,8 @@ namespace stream /** how many connections per minute did each identity have */ std::map m_Conns; boost::asio::deadline_timer m_ConnTrackTimer; - uint32_t m_ConnsPerMinute; - /** banned identities */ - std::vector m_Banned; - uint64_t m_LastBanClear; i2p::util::MemoryPool m_PacketsPool; - bool m_EnableDrop; public: diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index fb8fff97..b04ab885 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -567,7 +567,7 @@ namespace client bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); @@ -618,8 +618,6 @@ namespace client else // regular server tunnel by default serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip); - LogPrint(eLogInfo, "Clients: Set Max Conns To ", maxConns); - serverTunnel->SetMaxConnsPerMinute(maxConns); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 1bdf8bb5..0cff9ad5 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -280,8 +280,6 @@ namespace client const char* GetName() { return m_Name.c_str (); } - void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); } - private: void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, std::shared_ptr resolver); From eefbbd4efed3db5300a7593eb12d3d7b32dafd66 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 16 Apr 2018 09:47:35 -0400 Subject: [PATCH 023/115] remove all related streaming limit members --- libi2pd/Streaming.cpp | 8 +------- libi2pd/Streaming.h | 5 ----- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index afcda9ec..dd8e3634 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -903,8 +903,7 @@ namespace stream StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_LastIncomingReceiveStreamID (0), - m_PendingIncomingTimer (m_Owner->GetService ()), - m_ConnTrackTimer(m_Owner->GetService()) + m_PendingIncomingTimer (m_Owner->GetService ()) { } @@ -927,15 +926,10 @@ namespace stream ResetAcceptor (); m_PendingIncomingTimer.cancel (); m_PendingIncomingStreams.clear (); - m_ConnTrackTimer.cancel(); { std::unique_lock l(m_StreamsMutex); m_Streams.clear (); } - { - std::unique_lock l(m_ConnsMutex); - m_Conns.clear (); - } } void StreamingDestination::HandleNextPacket (Packet * packet) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9ce7e210..47f99833 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -280,11 +280,6 @@ namespace stream boost::asio::deadline_timer m_PendingIncomingTimer; std::map > m_SavedPackets; // receiveStreamID->packets, arrived before SYN - std::mutex m_ConnsMutex; - /** how many connections per minute did each identity have */ - std::map m_Conns; - boost::asio::deadline_timer m_ConnTrackTimer; - i2p::util::MemoryPool m_PacketsPool; public: From 0c661e7373c4463cfce31f70fd9c574f7d9f12fb Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Apr 2018 15:08:06 -0400 Subject: [PATCH 024/115] save new local destination for failed insert --- libi2pd_client/ClientContext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index b04ab885..6c3a9410 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -531,6 +531,7 @@ namespace client LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); } + auto clientTunnelDest = clientTunnel->GetLocalDestination (); // make copy of destination for possible update auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))); if (ins.second) { @@ -540,10 +541,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) + if (ins.first->second->GetLocalDestination () != clientTunnelDest) { LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); - ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); + ins.first->second->SetLocalDestination (clientTunnelDest); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); @@ -639,6 +640,7 @@ namespace client while (comma != std::string::npos); serverTunnel->SetAccessList (idents); } + auto serverTunnelDest = serverTunnel->GetLocalDestination (); auto ins = m_ServerTunnels.insert (std::make_pair ( std::make_pair (localDestination->GetIdentHash (), inPort), std::unique_ptr(serverTunnel))); @@ -650,10 +652,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) + if (ins.first->second->GetLocalDestination () != serverTunnelDest) { LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); - ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); + ins.first->second->SetLocalDestination (serverTunnelDest); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); From e2da16e9c32d2d7be8a1ec24fb03938653abbc61 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 19 Apr 2018 19:46:00 +0300 Subject: [PATCH 025/115] moved reseed out --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index d9cc6dec..126de7fc 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -191,7 +191,7 @@ namespace config { // "https://uk.reseed.i2p2.no:444/," // mamoth's shit "https://i2p-0.manas.ca:8443/," "https://download.xxlspeed.com/," - "https://reseed-ru.lngserv.ru/," + "https://reseed-fr.i2pd.xyz/," "https://reseed.atomike.ninja/," "https://reseed.memcpy.io/," "https://reseed.onion.im/," From 6916147dda4a4b46a1049d38bf81b5c6c9abb264 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sat, 21 Apr 2018 21:48:42 +0300 Subject: [PATCH 026/115] Few cents to get fullly console i2pd under Android --- android/i2pd/Android.mk | 74 +++++++++++++++++++++++++++++++++++++ android/i2pd/Application.mk | 42 +++++++++++++++++++++ daemon/Daemon.h | 13 ------- daemon/UnixDaemon.cpp | 3 ++ 4 files changed, 119 insertions(+), 13 deletions(-) create mode 100755 android/i2pd/Android.mk create mode 100755 android/i2pd/Application.mk diff --git a/android/i2pd/Android.mk b/android/i2pd/Android.mk new file mode 100755 index 00000000..ae56110c --- /dev/null +++ b/android/i2pd/Android.mk @@ -0,0 +1,74 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := i2pd +LOCAL_CPP_FEATURES := rtti exceptions +LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH) +LOCAL_STATIC_LIBRARIES := \ + boost_system \ + boost_date_time \ + boost_filesystem \ + boost_program_options \ + crypto ssl \ + miniupnpc +LOCAL_LDLIBS := -lz + +LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ + $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ + $(DAEMON_SRC_PATH)/Daemon.cpp \ + $(DAEMON_SRC_PATH)/UPnP.cpp \ + $(DAEMON_SRC_PATH)/HTTPServer.cpp \ + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/i2pd.cpp +include $(BUILD_EXECUTABLE) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_system +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_62_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_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_62_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_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_62_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_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_62_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := crypto +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.0e/$(TARGET_ARCH_ABI)/lib/libcrypto.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.0e/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := ssl +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.0e/$(TARGET_ARCH_ABI)/lib/libssl.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.0e/include +LOCAL_STATIC_LIBRARIES := crypto +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := miniupnpc +LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include +include $(PREBUILT_STATIC_LIBRARY) diff --git a/android/i2pd/Application.mk b/android/i2pd/Application.mk new file mode 100755 index 00000000..acc6f895 --- /dev/null +++ b/android/i2pd/Application.mk @@ -0,0 +1,42 @@ +#APP_ABI := all +#APP_ABI := armeabi-v7a x86 +#APP_ABI := x86 +#APP_ABI := x86_64 +APP_ABI := armeabi-v7a +#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. +APP_PLATFORM := android-14 + +# http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse +NDK_TOOLCHAIN_VERSION := 4.9 +# APP_STL := stlport_shared --> does not seem to contain C++11 features +#APP_STL := gnustl_shared +APP_STL := gnustl_static + +# Enable c++11 extensions in source code +APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE + +APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_LDFLAGS += -rdynamic -fPIE -pie +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +APP_CPPFLAGS += -DANDROID_ARM7A +endif + +APP_OPTIM := debug + +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# 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 +# change to your own +I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt +OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs + +# don't change me +I2PD_SRC_PATH = $(PWD)/.. + +LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd +LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client +DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 48301e73..f3e72904 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -44,19 +44,6 @@ namespace util } }; -#elif defined(ANDROID) -#define Daemon i2p::util::DaemonAndroid::Instance() - // dummy, invoked from android/jni/DaemonAndroid.* - class DaemonAndroid: public i2p::util::Daemon_Singleton - { - public: - static DaemonAndroid& Instance() - { - static DaemonAndroid instance; - return instance; - } - }; - #elif defined(_WIN32) #define Daemon i2p::util::DaemonWin32::Instance() class DaemonWin32 : public Daemon_Singleton diff --git a/daemon/UnixDaemon.cpp b/daemon/UnixDaemon.cpp index a9c48fee..3dd38fba 100644 --- a/daemon/UnixDaemon.cpp +++ b/daemon/UnixDaemon.cpp @@ -138,11 +138,14 @@ namespace i2p LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); return false; } + +#ifndef ANDROID if (lockf(pidFH, F_TLOCK, 0) != 0) { LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno)); return false; } +#endif char pid[10]; sprintf(pid, "%d\n", getpid()); ftruncate(pidFH, 0); From faac35cd1e868d888bba722164b7b3037af0ce46 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sat, 21 Apr 2018 21:55:45 +0300 Subject: [PATCH 027/115] Revert "Change jni to build executable. Clone with minimal changes DaemonUnix into DaemonAndroid" This reverts commit f11266972e81a6db65aeecc3f77fe2b47418385c. --- android/jni/Android.mk | 8 +- android/jni/Application.mk | 8 +- android/jni/DaemonAndroid.cpp | 366 +++++++++++----------- android/jni/DaemonAndroid.h | 113 ++++--- android/jni/i2pd_android.cpp | 66 ++++ android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 33 ++ 6 files changed, 359 insertions(+), 235 deletions(-) create mode 100755 android/jni/i2pd_android.cpp create mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 90284995..d5a8f05f 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -12,15 +12,15 @@ LOCAL_STATIC_LIBRARIES := \ miniupnpc LOCAL_LDLIBS := -lz -LOCAL_SRC_FILES := DaemonAndroid.cpp $(IFADDRS_PATH)/ifaddrs.c \ +LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \ $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/Daemon.cpp \ $(DAEMON_SRC_PATH)/UPnP.cpp \ $(DAEMON_SRC_PATH)/HTTPServer.cpp \ - $(DAEMON_SRC_PATH)/I2PControl.cpp \ - $(DAEMON_SRC_PATH)/i2pd.cpp -include $(BUILD_EXECUTABLE) + $(DAEMON_SRC_PATH)/I2PControl.cpp + +include $(BUILD_SHARED_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index acc6f895..0fa116c2 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,14 +9,12 @@ APP_PLATFORM := android-14 # http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse NDK_TOOLCHAIN_VERSION := 4.9 # APP_STL := stlport_shared --> does not seem to contain C++11 features -#APP_STL := gnustl_shared -APP_STL := gnustl_static +APP_STL := gnustl_shared # Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE +APP_CPPFLAGS += -std=c++11 APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP -APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif @@ -28,7 +26,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +I2PD_LIBS_PATH = /path/to/libraries BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 94c679be..75584740 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,193 +1,193 @@ #include "DaemonAndroid.h" - -#ifndef _WIN32 - -#include -#include -#include -#include -#include -#include -#include - -#include "Config.h" -#include "FS.h" -#include "Log.h" -#include "Tunnel.h" -#include "RouterContext.h" -#include "ClientContext.h" - -void handle_signal(int sig) -{ - switch (sig) - { - case SIGHUP: - LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration..."); - i2p::client::context.ReloadConfig(); - break; - case SIGUSR1: - LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs..."); - i2p::log::Logger().Reopen (); - break; - case SIGINT: - if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) - { - i2p::context.SetAcceptsTunnels (false); - Daemon.gracefulShutdownInterval = 10*60; // 10 minutes - LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); - } - else - Daemon.running = 0; - break; - case SIGABRT: - case SIGTERM: - Daemon.running = 0; // Exit loop - break; - case SIGPIPE: - LogPrint(eLogInfo, "SIGPIPE received"); - break; - } -} +#include "Daemon.h" +#include +#include +#include +#include +//#include "mainwindow.h" namespace i2p { - namespace util +namespace android +{ +/* Worker::Worker (DaemonAndroidImpl& daemon): + m_Daemon (daemon) { - bool DaemonAndroid::start() - { - if (isDaemon) - { - pid_t pid; - pid = fork(); - if (pid > 0) // parent - ::exit (EXIT_SUCCESS); + } - if (pid < 0) // error - { - LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); - return false; - } + void Worker::startDaemon() + { + Log.d(TAG"Performing daemon start..."); + m_Daemon.start(); + Log.d(TAG"Daemon started."); + emit resultReady(); + } + void Worker::restartDaemon() + { + Log.d(TAG"Performing daemon restart..."); + m_Daemon.restart(); + Log.d(TAG"Daemon restarted."); + emit resultReady(); + } + void Worker::stopDaemon() { + Log.d(TAG"Performing daemon stop..."); + m_Daemon.stop(); + Log.d(TAG"Daemon stopped."); + emit resultReady(); + } - // child - umask(S_IWGRP | S_IRWXO); // 0027 - int sid = setsid(); - if (sid < 0) - { - LogPrint(eLogError, "Daemon: could not create process group."); - return false; - } - std::string d = i2p::fs::GetDataDir(); - if (chdir(d.c_str()) != 0) - { - LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); - return false; - } - - // point std{in,out,err} descriptors to /dev/null - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); - } - - // set proc limits - struct rlimit limit; - uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); - getrlimit(RLIMIT_NOFILE, &limit); - if (nfiles == 0) { - LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); - } else if (nfiles <= limit.rlim_max) { - limit.rlim_cur = nfiles; - if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { - LogPrint(eLogInfo, "Daemon: set max number of open files to ", - nfiles, " (system limit is ", limit.rlim_max, ")"); - } else { - LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); - } - } else { - LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); - } - uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); - if (cfsize) // core file size set - { - cfsize *= 1024; - getrlimit(RLIMIT_CORE, &limit); - if (cfsize <= limit.rlim_max) { - limit.rlim_cur = cfsize; - if (setrlimit(RLIMIT_CORE, &limit) != 0) { - LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); - } else if (cfsize == 0) { - LogPrint(eLogInfo, "Daemon: coredumps disabled"); - } else { - LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); - } - } else { - LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); - } - } - - // Pidfile - // this code is c-styled and a bit ugly - std::string pidfile; i2p::config::GetOption("pidfile", pidfile); - if (pidfile == "") { - pidfile = i2p::fs::DataDirPath("i2pd.pid"); - } - if (pidfile != "") { - pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); - if (pidFH < 0) - { - LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); - return false; - } - char pid[10]; - sprintf(pid, "%d\n", getpid()); - ftruncate(pidFH, 0); - if (write(pidFH, pid, strlen(pid)) < 0) - { - LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); - return false; - } - } - gracefulShutdownInterval = 0; // not specified - - // Signal handler - struct sigaction sa; - sa.sa_handler = handle_signal; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGHUP, &sa, 0); - sigaction(SIGUSR1, &sa, 0); - sigaction(SIGABRT, &sa, 0); - sigaction(SIGTERM, &sa, 0); - sigaction(SIGINT, &sa, 0); - sigaction(SIGPIPE, &sa, 0); - - return Daemon_Singleton::start(); - } - - bool DaemonAndroid::stop() - { - i2p::fs::Remove(pidfile); - - return Daemon_Singleton::stop(); - } - - void DaemonAndroid::run () - { - while (running) - { - std::this_thread::sleep_for (std::chrono::seconds(1)); - if (gracefulShutdownInterval) - { - gracefulShutdownInterval--; // - 1 second - if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0) - { - LogPrint(eLogInfo, "Graceful shutdown"); - return; - } - } - } + Controller::Controller(DaemonAndroidImpl& daemon): + m_Daemon (daemon) + { + Worker *worker = new Worker (m_Daemon); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); + connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); + connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); + connect(worker, &Worker::resultReady, this, &Controller::handleResults); + workerThread.start(); + } + Controller::~Controller() + { + Log.d(TAG"Closing and waiting for daemon worker thread..."); + workerThread.quit(); + workerThread.wait(); + Log.d(TAG"Waiting for daemon worker thread finished."); + if(m_Daemon.isRunning()) + { + Log.d(TAG"Stopping the daemon..."); + m_Daemon.stop(); + Log.d(TAG"Stopped the daemon."); } } -} +*/ + DaemonAndroidImpl::DaemonAndroidImpl () + //: + /*mutex(nullptr), */ + //m_IsRunning(false), + //m_RunningChangedCallback(nullptr) + { + } -#endif + DaemonAndroidImpl::~DaemonAndroidImpl () + { + //delete mutex; + } + + bool DaemonAndroidImpl::init(int argc, char* argv[]) + { + //mutex=new QMutex(QMutex::Recursive); + //setRunningCallback(0); + //m_IsRunning=false; + return Daemon.init(argc,argv); + } + + void DaemonAndroidImpl::start() + { + //QMutexLocker locker(mutex); + //setRunning(true); + Daemon.start(); + } + + void DaemonAndroidImpl::stop() + { + //QMutexLocker locker(mutex); + Daemon.stop(); + //setRunning(false); + } + + void DaemonAndroidImpl::restart() + { + //QMutexLocker locker(mutex); + stop(); + start(); + } + /* + void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) + { + m_RunningChangedCallback = cb; + } + + bool DaemonAndroidImpl::isRunning() + { + return m_IsRunning; + } + + void DaemonAndroidImpl::setRunning(bool newValue) + { + bool oldValue = m_IsRunning; + if(oldValue!=newValue) + { + m_IsRunning = newValue; + if(m_RunningChangedCallback) + m_RunningChangedCallback(); + } + } +*/ + static DaemonAndroidImpl daemon; + static char* argv[1]={strdup("tmp")}; + /** + * returns error details if failed + * returns "ok" if daemon initialized and started okay + */ + std::string start(/*int argc, char* argv[]*/) + { + try + { + //int result; + + { + //Log.d(TAG"Initialising the daemon..."); + bool daemonInitSuccess = daemon.init(1,argv); + if(!daemonInitSuccess) + { + //QMessageBox::critical(0, "Error", "Daemon init failed"); + return "Daemon init failed"; + } + //Log.d(TAG"Initialised, creating the main window..."); + //MainWindow w; + //Log.d(TAG"Before main window.show()..."); + //w.show (); + + { + //i2p::qt::Controller daemonQtController(daemon); + //Log.d(TAG"Starting the daemon..."); + //emit daemonQtController.startDaemon(); + //daemon.start (); + //Log.d(TAG"Starting GUI event loop..."); + //result = app.exec(); + //daemon.stop (); + daemon.start(); + } + } + + //QMessageBox::information(&w, "Debug", "demon stopped"); + //Log.d(TAG"Exiting the application"); + //return result; + } + catch (boost::exception& ex) + { + std::stringstream ss; + ss << boost::diagnostic_information(ex); + return ss.str(); + } + catch (std::exception& ex) + { + std::stringstream ss; + ss << ex.what(); + return ss.str(); + } + catch(...) + { + return "unknown exception"; + } + return "ok"; + } + + void stop() + { + daemon.stop(); + } +} +} diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index c62d7c76..9cc8219b 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -1,60 +1,87 @@ -#ifndef DAEMON_H__ -#define DAEMON_H__ +#ifndef DAEMON_ANDROID_H +#define DAEMON_ANDROID_H -#include #include namespace i2p { -namespace util +namespace android { - class Daemon_Singleton_Private; - class Daemon_Singleton - { - public: - virtual bool init(int argc, char* argv[]); - virtual bool start(); - virtual bool stop(); - virtual void run () {}; + class DaemonAndroidImpl + { + public: - bool isDaemon; - bool running; + DaemonAndroidImpl (); + ~DaemonAndroidImpl (); - protected: - Daemon_Singleton(); - virtual ~Daemon_Singleton(); + //typedef void (*runningChangedCallback)(); - bool IsService () const; + /** + * @return success + */ + bool init(int argc, char* argv[]); + void start(); + void stop(); + void restart(); + //void setRunningCallback(runningChangedCallback cb); + //bool isRunning(); + private: + //void setRunning(bool running); + private: + //QMutex* mutex; + //bool m_IsRunning; + //runningChangedCallback m_RunningChangedCallback; + }; - // d-pointer for httpServer, httpProxy, etc. - class Daemon_Singleton_Private; - Daemon_Singleton_Private &d; - }; + /** + * returns "ok" if daemon init failed + * returns errinfo if daemon initialized and started okay + */ + std::string start(); -#if defined(ANDROID) -#define Daemon i2p::util::DaemonAndroid::Instance() - class DaemonAndroid : public Daemon_Singleton - { - public: - static DaemonAndroid& Instance() - { - static DaemonAndroid instance; - return instance; - } + // stops the daemon + void stop(); - bool start(); - bool stop(); - void run (); + /* + class Worker : public QObject + { + Q_OBJECT + public: - private: - std::string pidfile; - int pidFH; + Worker (DaemonAndroidImpl& daemon); - public: - int gracefulShutdownInterval; // in seconds - }; -#endif + private: + + DaemonAndroidImpl& m_Daemon; + + public slots: + void startDaemon(); + void restartDaemon(); + void stopDaemon(); + + signals: + void resultReady(); + }; + + class Controller : public QObject + { + Q_OBJECT + QThread workerThread; + public: + Controller(DaemonAndroidImpl& daemon); + ~Controller(); + private: + DaemonAndroidImpl& m_Daemon; + + public slots: + void handleResults(){} + signals: + void startDaemon(); + void stopDaemon(); + void restartDaemon(); + }; + */ } } -#endif // DAEMON_H__ +#endif // DAEMON_ANDROID_H diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp new file mode 100755 index 00000000..8791c90b --- /dev/null +++ b/android/jni/i2pd_android.cpp @@ -0,0 +1,66 @@ + +//#include +#include +#include "org_purplei2p_i2pd_I2PD_JNI.h" +#include "DaemonAndroid.h" +#include "RouterContext.h" +#include "Transports.h" + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv * env, jclass clazz) { +#if defined(__arm__) + #if defined(__ARM_ARCH_7A__) + #if defined(__ARM_NEON__) + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a/NEON (hard-float)" + #else + #define ABI "armeabi-v7a/NEON" + #endif + #else + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a (hard-float)" + #else + #define ABI "armeabi-v7a" + #endif + #endif + #else + #define ABI "armeabi" + #endif +#elif defined(__i386__) + #define ABI "x86" +#elif defined(__x86_64__) + #define ABI "x86_64" +#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ + #define ABI "mips64" +#elif defined(__mips__) + #define ABI "mips" +#elif defined(__aarch64__) + #define ABI "arm64-v8a" +#else + #define ABI "unknown" +#endif + + return env->NewStringUTF(ABI); +} + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv * env, jclass clazz) { + return env->NewStringUTF(i2p::android::start().c_str()); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv * env, jclass clazz) { + i2p::android::stop(); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv * env, jclass clazz) { + i2p::context.SetAcceptsTunnels (false); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv * env, jclass clazz, jboolean isConnected) +{ + bool isConnectedBool = (bool) isConnected; + i2p::transport::transports.SetOnline (isConnectedBool); +} diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h new file mode 100644 index 00000000..04923d22 --- /dev/null +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -0,0 +1,33 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_purplei2p_i2pd_I2PD_JNI */ + +#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI +#define _Included_org_purplei2p_i2pd_I2PD_JNI +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_purplei2p_i2pd_I2PD_JNI + * Method: stringFromJNI + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv *, jclass); + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv * env, jclass clazz, jboolean isConnected); + +#ifdef __cplusplus +} +#endif +#endif From c8de7aa23c5a17c35520e7606459da4e9e770111 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Tue, 24 Apr 2018 01:40:12 +0800 Subject: [PATCH 028/115] qt now statically compiles for win32 --- qt/i2pd_qt/ServerTunnelPane.cpp | 18 ------------------ qt/i2pd_qt/ServerTunnelPane.h | 13 ------------- qt/i2pd_qt/TunnelConfig.cpp | 3 +-- qt/i2pd_qt/TunnelConfig.h | 6 ------ qt/i2pd_qt/i2pd_qt.pro | 23 ++++++++++++++++++++--- qt/i2pd_qt/mainwindow.h | 4 ---- 6 files changed, 21 insertions(+), 46 deletions(-) diff --git a/qt/i2pd_qt/ServerTunnelPane.cpp b/qt/i2pd_qt/ServerTunnelPane.cpp index 029a3ea2..bc6389a9 100644 --- a/qt/i2pd_qt/ServerTunnelPane.cpp +++ b/qt/i2pd_qt/ServerTunnelPane.cpp @@ -204,24 +204,6 @@ int ServerTunnelPane::appendServerTunnelForm( horizontalLayout_2->addItem(horizontalSpacer); tunnelGridLayout->addLayout(horizontalLayout_2); } - { - uint32_t maxConns = tunnelConfig->getmaxConns(); - QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); - ui.maxConnsLabel = new QLabel(gridLayoutWidget_2); - maxConnsLabel->setObjectName(QStringLiteral("maxConnsLabel")); - horizontalLayout_2->addWidget(maxConnsLabel); - ui.maxConnsLineEdit = new QLineEdit(gridLayoutWidget_2); - maxConnsLineEdit->setObjectName(QStringLiteral("maxConnsLineEdit")); - maxConnsLineEdit->setText(QString::number(maxConns)); - maxConnsLineEdit->setMaximumWidth(80); - QObject::connect(maxConnsLineEdit, SIGNAL(textChanged(const QString &)), - this, SLOT(updated())); - horizontalLayout_2->addWidget(maxConnsLineEdit); - QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - horizontalLayout_2->addItem(horizontalSpacer); - tunnelGridLayout->addLayout(horizontalLayout_2); - } { std::string address = tunnelConfig->getaddress(); QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h index 556c8473..0a07267b 100644 --- a/qt/i2pd_qt/ServerTunnelPane.h +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -81,10 +81,6 @@ private: QLabel * addressLabel; QLineEdit * addressLineEdit; - //maxConns - QLabel * maxConnsLabel; - QLineEdit * maxConnsLineEdit; - //gzip QCheckBox * gzipCheckBox; @@ -109,7 +105,6 @@ private: hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0)); webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0)); addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0)); - maxConnsLabel->setText(QApplication::translate("srvTunForm", "Max connections:", 0)); gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0)); isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0)); @@ -152,14 +147,6 @@ protected: stc->setaddress(addressLineEdit->text().toStdString()); - auto mcStr=maxConnsLineEdit->text(); - uint32_t mcInt=(uint32_t)mcStr.toInt(&ok); - if(!ok){ - highlightWrongInput(QApplication::tr("Bad maxConns, must be int.")+" "+cannotSaveSettings,maxConnsLineEdit); - return false; - } - stc->setmaxConns(mcInt); - stc->setgzip(gzipCheckBox->isChecked()); stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked()); diff --git a/qt/i2pd_qt/TunnelConfig.cpp b/qt/i2pd_qt/TunnelConfig.cpp index 81216c0b..e4354b62 100644 --- a/qt/i2pd_qt/TunnelConfig.cpp +++ b/qt/i2pd_qt/TunnelConfig.cpp @@ -48,7 +48,6 @@ void ServerTunnelConfig::saveToStringStream(std::stringstream& out) { << "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n" << "address=" << address << "\n" << "hostoverride=" << hostOverride << "\n" - << "webircpassword=" << webircpass << "\n" - << "maxconns=" << maxConns << "\n"; + << "webircpassword=" << webircpass << "\n"; } diff --git a/qt/i2pd_qt/TunnelConfig.h b/qt/i2pd_qt/TunnelConfig.h index c714a4f5..58a1fa0b 100644 --- a/qt/i2pd_qt/TunnelConfig.h +++ b/qt/i2pd_qt/TunnelConfig.h @@ -148,7 +148,6 @@ public: std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); # * inport -- optional, i2p service port, if unset - the same as 'port' @@ -170,7 +169,6 @@ class ServerTunnelConfig : public TunnelConfig { std::string webircpass; bool gzip; i2p::data::SigningKeyType sigType; - uint32_t maxConns; std::string address; bool isUniqueLocal; public: @@ -184,7 +182,6 @@ public: std::string webircpass_, bool gzip_, i2p::data::SigningKeyType sigType_, - uint32_t maxConns_, std::string address_, bool isUniqueLocal_): TunnelConfig(name_, type_, i2cpParameters_), host(host_), @@ -196,7 +193,6 @@ public: webircpass(webircpass_), gzip(gzip_), sigType(sigType_), - maxConns(maxConns_), address(address_), isUniqueLocal(isUniqueLocal_) {} std::string& gethost(){return host;} @@ -208,7 +204,6 @@ public: std::string& getwebircpass(){return webircpass;} bool getgzip(){return gzip;} i2p::data::SigningKeyType getsigType(){return sigType;} - uint32_t getmaxConns(){return maxConns;} std::string& getaddress(){return address;} bool getisUniqueLocal(){return isUniqueLocal;} void sethost(const std::string& host_){host=host_;} @@ -220,7 +215,6 @@ public: void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;} void setgzip(bool gzip_){gzip=gzip_;} void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} - void setmaxConns(uint32_t maxConns_){maxConns=maxConns_;} void setaddress(const std::string& address_){address=address_;} void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;} virtual void saveToStringStream(std::stringstream& out); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 941dfff3..b46cfa38 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -272,10 +272,27 @@ linux:!android { LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc } -windows:!android { +windows { message("Using Windows settings") - DEFINES += BOOST_USE_WINDOWS_H WINDOWS - LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc + DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB + DEFINES -= UNICODE _UNICODE + BOOST_SUFFIX = -mt + QMAKE_LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + LIBS = -lminiupnpc \ + -lboost_system$$BOOST_SUFFIX \ + -lboost_date_time$$BOOST_SUFFIX \ + -lboost_filesystem$$BOOST_SUFFIX \ + -lboost_program_options$$BOOST_SUFFIX \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread } !android:!symbian:!maemo5:!simulator { diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index cac97a1f..c5f0c902 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -628,7 +628,6 @@ private: std::string webircpass = ""; bool gzip = true; i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256; - uint32_t maxConns = i2p::stream::DEFAULT_MAX_CONNS_PER_MIN; std::string address = "127.0.0.1"; bool isUniqueLocal = true; @@ -646,7 +645,6 @@ private: webircpass, gzip, sigType, - maxConns, address, isUniqueLocal); @@ -734,7 +732,6 @@ private: std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); @@ -769,7 +766,6 @@ private: webircpass, gzip, sigType, - maxConns, address, isUniqueLocal); } From a2b3ee53e085bf40b35d49629efe38ab1e349daa Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Apr 2018 14:39:46 -0400 Subject: [PATCH 029/115] fixed build error --- daemon/Daemon.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/daemon/Daemon.h b/daemon/Daemon.h index f3e72904..4491d303 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -64,7 +64,18 @@ namespace util DaemonWin32 ():isGraceful(false) {} }; - +#elif defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + // dummy, invoked from android/jni/DaemonAndroid.* + class DaemonAndroid: public i2p::util::Daemon_Singleton + { + public: + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } + }; #else #define Daemon i2p::util::DaemonLinux::Instance() class DaemonLinux : public Daemon_Singleton From 396cba7339b9dda8f9f13c4743bdfc216c0b4658 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 24 Apr 2018 03:19:02 +0300 Subject: [PATCH 030/115] fix static building on windows, add resource files (closes #1163) --- qt/i2pd_qt/i2pd.qrc | 7 +++-- qt/i2pd_qt/i2pd.rc | 32 +++++++++++++++++++++ qt/i2pd_qt/i2pd_qt.pro | 4 ++- qt/i2pd_qt/mainwindow.cpp | 2 +- qt/i2pd_qt/resources/icons/mask.ico | Bin 0 -> 156564 bytes qt/i2pd_qt/{ => resources}/images/icon.png | Bin 6 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 qt/i2pd_qt/i2pd.rc create mode 100644 qt/i2pd_qt/resources/icons/mask.ico rename qt/i2pd_qt/{ => resources}/images/icon.png (100%) diff --git a/qt/i2pd_qt/i2pd.qrc b/qt/i2pd_qt/i2pd.qrc index 2abdeb05..4e5523e9 100644 --- a/qt/i2pd_qt/i2pd.qrc +++ b/qt/i2pd_qt/i2pd.qrc @@ -1,5 +1,6 @@ - - images/icon.png - + + resources/icons/mask.ico + resources/images/icon.png + diff --git a/qt/i2pd_qt/i2pd.rc b/qt/i2pd_qt/i2pd.rc new file mode 100644 index 00000000..bebdf1d6 --- /dev/null +++ b/qt/i2pd_qt/i2pd.rc @@ -0,0 +1,32 @@ +IDI_ICON1 ICON DISCARDABLE "resources/icons/mask.ico" + +#include // needed for VERSIONINFO +#include "../../libi2pd/version.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH +PRODUCTVERSION I2P_VERSION_MAJOR,I2P_VERSION_MINOR,I2P_VERSION_MICRO,I2P_VERSION_PATCH +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "PurpleI2P" + VALUE "FileDescription", "I2Pd Qt" + VALUE "FileVersion", I2PD_VERSION + VALUE "InternalName", "i2pd-qt" + VALUE "LegalCopyright", "Copyright (C) 2013-2018, The PurpleI2P Project" + VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause." + VALUE "OriginalFilename", "i2pd_qt.exe" + VALUE "ProductName", "i2pd-qt" + VALUE "ProductVersion", I2P_VERSION + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index b46cfa38..21ef6358 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -274,10 +274,12 @@ linux:!android { windows { message("Using Windows settings") + RC_FILE = i2pd.rc DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB DEFINES -= UNICODE _UNICODE BOOST_SUFFIX = -mt - QMAKE_LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + QMAKE_CXXFLAGS = -Os + QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows LIBS = -lminiupnpc \ -lboost_system$$BOOST_SUFFIX \ diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index fc1e5985..c3761764 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -449,7 +449,7 @@ void MainWindow::createTrayIcon() { } void MainWindow::setIcon() { - QIcon icon(":/images/icon.png"); + QIcon icon(":icons/mask"); trayIcon->setIcon(icon); setWindowIcon(icon); diff --git a/qt/i2pd_qt/resources/icons/mask.ico b/qt/i2pd_qt/resources/icons/mask.ico new file mode 100644 index 0000000000000000000000000000000000000000..f5807de5ccae7dae7b7234badc651a7a57b62367 GIT binary patch literal 156564 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%0AO>91EHxccO^29Yysmoh8MthpVdk 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%0A2cpAh53rB_uKqdNWrzK_ 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 K0(OBOy!U^N3-aIq literal 0 HcmV?d00001 diff --git a/qt/i2pd_qt/images/icon.png b/qt/i2pd_qt/resources/images/icon.png similarity index 100% rename from qt/i2pd_qt/images/icon.png rename to qt/i2pd_qt/resources/images/icon.png From 4643c92d33a1d43861b0aac74dec2f01689d01bf Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 09:45:16 -0400 Subject: [PATCH 031/115] Initial SAM cleanup --- daemon/HTTPServer.cpp | 2 +- daemon/I2PControl.cpp | 2 +- libi2pd/Streaming.cpp | 4 +- libi2pd/Streaming.h | 3 + libi2pd_client/SAM.cpp | 208 ++++++++++++++++++----------------------- libi2pd_client/SAM.h | 52 ++++------- 6 files changed, 118 insertions(+), 153 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 6f884a9b..554ba45d 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -649,7 +649,7 @@ namespace http { s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n"; s << "
\r\n"; s << "Streams:
\r\n"; - for (const auto& it: session->ListSockets()) + for (const auto& it: sam->ListSockets(id)) { switch (it->GetSocketType ()) { diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index fcff78cd..6ac87cbb 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -727,7 +727,7 @@ namespace client sam_session.put("name", name); sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - for (const auto& socket: it.second->ListSockets()) + for (const auto& socket: sam->ListSockets(it.first)) { boost::property_tree::ptree stream; stream.put("type", socket->GetSocketType ()); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index dd8e3634..e8386b61 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -578,9 +578,7 @@ namespace stream if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) // nothing to send { m_Status = eStreamStatusClosed; - // close could be called from another thread so do SendClose from the destination thread - // this is so m_LocalDestination.NewPacket () does not trigger a race condition - m_Service.post(std::bind(&Stream::SendClose, shared_from_this())); + SendClose(); } break; case eStreamStatusClosed: diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 47f99833..7f2598c0 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -165,6 +165,9 @@ namespace stream void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; + void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; + + /** only call close from destination thread, use Stream::AsyncClose for other threads */ void Close (); void Cancel () { m_ReceiveTimer.cancel (); }; diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 05943981..b8a72f0c 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -15,8 +15,8 @@ namespace i2p { namespace client { - SAMSocket::SAMSocket (SAMBridge& owner, std::shared_ptr socket): - m_Owner (owner), m_Socket(socket), m_Timer (m_Owner.GetService ()), + SAMSocket::SAMSocket (SAMBridge& owner): + m_Owner (owner), m_Socket(owner.GetService()), m_Timer (m_Owner.GetService ()), m_BufferOffset (0), m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false), m_IsAccepting (false), m_Stream (nullptr) @@ -25,51 +25,18 @@ namespace client SAMSocket::~SAMSocket () { - if(m_Stream) - { - m_Stream->Close (); - m_Stream.reset (); - } - auto Session = m_Owner.FindSession(m_ID); - - switch (m_SocketType) - { - case eSAMSocketTypeSession: - m_Owner.CloseSession (m_ID); - break; - case eSAMSocketTypeStream: - { - if (Session) - Session->DelSocket (this); - break; - } - case eSAMSocketTypeAcceptor: - { - if (Session) - { - Session->DelSocket (this); - if (m_IsAccepting && Session->localDestination) - Session->localDestination->StopAcceptingStreams (); - } - break; - } - default: - ; - } - m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket && m_Socket->is_open()) m_Socket->close (); - m_Socket.reset (); + m_Stream.reset (); + if (m_Socket.is_open()) m_Socket.close (); } void SAMSocket::Terminate (const char* reason) { if(m_Stream) { - m_Stream->Close (); + m_Stream->AsyncClose (); m_Stream.reset (); } auto Session = m_Owner.FindSession(m_ID); - switch (m_SocketType) { case eSAMSocketTypeSession: @@ -77,15 +44,12 @@ namespace client break; case eSAMSocketTypeStream: { - if (Session) - Session->DelSocket (this); break; } case eSAMSocketTypeAcceptor: { if (Session) { - Session->DelSocket (this); if (m_IsAccepting && Session->localDestination) Session->localDestination->StopAcceptingStreams (); } @@ -95,16 +59,15 @@ namespace client ; } m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket && m_Socket->is_open()) m_Socket->close (); - m_Socket.reset (); + if (m_Socket.is_open()) m_Socket.close (); + m_Owner.RemoveSocket(this); } void SAMSocket::ReceiveHandshake () - { - if(m_Socket) - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), - std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); + { + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); } static bool SAMVersionAcceptable(const std::string & ver) @@ -125,7 +88,7 @@ namespace client void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: handshake read error"); @@ -184,7 +147,7 @@ namespace client #else size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ()); #endif - boost::asio::async_write (*m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -199,17 +162,22 @@ namespace client } } + bool SAMSocket::IsSession(const std::string & id) const + { + return id == m_ID; + } + void SAMSocket::HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: handshake reply send error"); } - else if(m_Socket) + else { - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), std::bind(&SAMSocket::HandleMessage, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -220,7 +188,7 @@ namespace client LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg); if (!m_IsSilent) - boost::asio::async_write (*m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, close)); else @@ -501,7 +469,6 @@ namespace client if(session) { m_SocketType = eSAMSocketTypeStream; - session->AddSocket (shared_from_this ()); m_Stream = session->localDestination->CreateStream (remote); m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send m_BufferOffset = 0; @@ -534,7 +501,6 @@ namespace client if (session) { m_SocketType = eSAMSocketTypeAcceptor; - session->AddSocket (shared_from_this ()); if (!session->localDestination->IsAcceptingStreams ()) { m_IsAccepting = true; @@ -704,17 +670,9 @@ namespace client void SAMSocket::Receive () { - if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE) - { - LogPrint (eLogError, "SAM: Buffer is full, terminate"); - Terminate ("Buffer is full"); - return; - } else if (m_Socket) - m_Socket->async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), - std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage, - shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - else - LogPrint(eLogError, "SAM: receive with no native socket"); + m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), + std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage, + shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -731,15 +689,12 @@ namespace client { bytes_transferred += m_BufferOffset; m_BufferOffset = 0; - auto s = shared_from_this (); m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred, - [s](const boost::system::error_code& ecode) - { - if (!ecode) - s->m_Owner.GetService ().post ([s] { s->Receive (); }); - else - s->m_Owner.GetService ().post ([s] { s->Terminate ("AsyncSend failed"); }); - }); + std::bind(&SAMSocket::HandleStreamSend, shared_from_this(), std::placeholders::_1)); + } + else + { + Terminate("No Stream Remaining"); } } } @@ -773,14 +728,11 @@ namespace client void SAMSocket::WriteI2PDataImmediate(uint8_t * buff, size_t sz) { - if(m_Socket) - boost::asio::async_write ( - *m_Socket, - boost::asio::buffer (buff, sz), - boost::asio::transfer_all(), - std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination - else - LogPrint(eLogError, "SAM: no native socket"); + boost::asio::async_write ( + m_Socket, + boost::asio::buffer (buff, sz), + boost::asio::transfer_all(), + std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination } void SAMSocket::HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff) @@ -858,7 +810,7 @@ namespace client if (session) { // find more pending acceptors - for (auto it: session->ListSockets ()) + for (auto it: m_Owner.ListSockets (m_ID)) if (it->m_SocketType == eSAMSocketTypeAcceptor) { it->m_IsAccepting = true; @@ -930,12 +882,19 @@ namespace client } } - SAMSession::SAMSession (std::shared_ptr dest): + void SAMSocket::HandleStreamSend(const boost::system::error_code & ec) + { + m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); + } + + SAMSession::SAMSession (SAMBridge & parent, const std::string & id, std::shared_ptr dest): + m_Bridge(parent), localDestination (dest), - UDPEndpoint(nullptr) + UDPEndpoint(nullptr), + Name(id) { } - + SAMSession::~SAMSession () { CloseStreams(); @@ -944,15 +903,10 @@ namespace client void SAMSession::CloseStreams () { - std::vector > socks; + for(const auto & itr : m_Bridge.ListSockets(Name)) { - std::lock_guard lock(m_SocketsMutex); - for (const auto& sock : m_Sockets) { - socks.push_back(sock); - } + itr->Terminate(nullptr); } - for (auto & sock : socks ) sock->Terminate("SAMSession::CloseStreams()"); - m_Sockets.clear(); } SAMBridge::SAMBridge (const std::string& address, int port): @@ -1009,12 +963,16 @@ namespace client void SAMBridge::Accept () { - auto native = std::make_shared(m_Service); - auto newSocket = std::make_shared (*this, native); - m_Acceptor.async_accept (*native, std::bind (&SAMBridge::HandleAccept, this, + auto newSocket = std::make_shared(*this); + m_Acceptor.async_accept (newSocket->GetSocket(), std::bind (&SAMBridge::HandleAccept, this, std::placeholders::_1, newSocket)); } + void SAMBridge::RemoveSocket(const SAMSocket * socket) + { + m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item.get() == socket; }); + } + void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) { if (!ecode) @@ -1024,6 +982,7 @@ namespace client if (!ec) { LogPrint (eLogDebug, "SAM: new connection from ", ep); + m_OpenSockets.push_back(socket); socket->ReceiveHandshake (); } else @@ -1066,7 +1025,7 @@ namespace client if (localDestination) { localDestination->Acquire (); - auto session = std::make_shared(localDestination); + auto session = std::make_shared(*this, id, localDestination); std::unique_lock l(m_SessionsMutex); auto ret = m_Sessions.insert (std::make_pair(id, session)); if (!ret.second) @@ -1105,6 +1064,18 @@ namespace client return nullptr; } + std::list > SAMBridge::ListSockets(const std::string & id) const + { + std::list > list; + { + std::unique_lock l(m_SessionsMutex); + for (const auto & itr : m_OpenSockets) + if (itr->IsSession(id)) + list.push_back(itr); + } + return list; + } + void SAMBridge::SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote) { if(remote) @@ -1127,33 +1098,38 @@ namespace client { m_DatagramReceiveBuffer[bytes_transferred] = 0; char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n'); - *eol = 0; eol++; - size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer); - LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen); - char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' '); - if (sessionID) + if(eol) { - sessionID++; - char * destination = strchr (sessionID, ' '); - if (destination) + *eol = 0; eol++; + size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer); + LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen); + char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' '); + if (sessionID) { - *destination = 0; destination++; - auto session = FindSession (sessionID); - if (session) + sessionID++; + char * destination = strchr (sessionID, ' '); + if (destination) { - i2p::data::IdentityEx dest; - dest.FromBase64 (destination); - session->localDestination->GetDatagramDestination ()-> - SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + *destination = 0; destination++; + auto session = FindSession (sessionID); + if (session) + { + i2p::data::IdentityEx dest; + dest.FromBase64 (destination); + session->localDestination->GetDatagramDestination ()-> + SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + } + else + LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); } else - LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); + LogPrint (eLogError, "SAM: Missing destination key"); } else - LogPrint (eLogError, "SAM: Missing destination key"); + LogPrint (eLogError, "SAM: Missing sessionID"); } else - LogPrint (eLogError, "SAM: Missing sessionID"); + LogPrint(eLogError, "SAM: invalid datagram"); ReceiveDatagram (); } else diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 6ecd14a4..d14e5e39 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -77,24 +77,27 @@ namespace client class SAMBridge; struct SAMSession; - class SAMSocket: public std::enable_shared_from_this + class SAMSocket :public std::enable_shared_from_this { public: typedef boost::asio::ip::tcp::socket Socket_t; - SAMSocket (SAMBridge& owner, std::shared_ptr socket); + SAMSocket (SAMBridge& owner); ~SAMSocket (); - boost::asio::ip::tcp::socket& GetSocket () { return *m_Socket; }; + Socket_t& GetSocket () { return m_Socket; }; void ReceiveHandshake (); void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; SAMSocketType GetSocketType () const { return m_SocketType; }; void Terminate (const char* reason); + bool IsSession(const std::string & id) const; + private: - - void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void TerminateClose() { Terminate(nullptr); } + + void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendMessageReply (const char * msg, size_t len, bool close); @@ -128,10 +131,12 @@ namespace client void WriteI2PDataImmediate(uint8_t * ptr, size_t sz); void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff); + void HandleStreamSend(const boost::system::error_code & ec); + private: SAMBridge& m_Owner; - std::shared_ptr m_Socket; + Socket_t m_Socket; boost::asio::deadline_timer m_Timer; char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1]; size_t m_BufferOffset; @@ -145,34 +150,12 @@ namespace client struct SAMSession { + SAMBridge & m_Bridge; std::shared_ptr localDestination; - std::list > m_Sockets; std::shared_ptr UDPEndpoint; - std::mutex m_SocketsMutex; + std::string Name; - /** safely add a socket to this session */ - void AddSocket(std::shared_ptr sock) { - std::lock_guard lock(m_SocketsMutex); - m_Sockets.push_back(sock); - } - - /** safely remove a socket from this session */ - void DelSocket(SAMSocket * sock) { - std::lock_guard lock(m_SocketsMutex); - m_Sockets.remove_if([sock](const std::shared_ptr s) -> bool { return s.get() == sock; }); - } - - /** get a list holding a copy of all sam sockets from this session */ - std::list > ListSockets() { - std::list > l; - { - std::lock_guard lock(m_SocketsMutex); - for(const auto& sock : m_Sockets ) l.push_back(sock); - } - return l; - } - - SAMSession (std::shared_ptr dest); + SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); ~SAMSession (); void CloseStreams (); @@ -194,15 +177,19 @@ namespace client void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; + std::list > ListSockets(const std::string & id) const; + /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); + void RemoveSocket(const SAMSocket * socket); + private: void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); void ReceiveDatagram (); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -217,6 +204,7 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; + std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; public: From b7a67b4b03c319fd9fc4432e2ac8751c75d5ff39 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 09:56:24 -0400 Subject: [PATCH 032/115] use refernce not copy --- libi2pd_client/SAM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index b8a72f0c..71b5bea1 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -810,7 +810,7 @@ namespace client if (session) { // find more pending acceptors - for (auto it: m_Owner.ListSockets (m_ID)) + for (auto & it: m_Owner.ListSockets (m_ID)) if (it->m_SocketType == eSAMSocketTypeAcceptor) { it->m_IsAccepting = true; From 60463fdafa97ba68f41430c78bb946ff41bbc1d7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:11:48 -0400 Subject: [PATCH 033/115] shut down socket and don't allocate buffer for each write in WriteI2PData --- libi2pd_client/SAM.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 71b5bea1..b0ffda51 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -25,8 +25,7 @@ namespace client SAMSocket::~SAMSocket () { - m_Stream.reset (); - if (m_Socket.is_open()) m_Socket.close (); + m_Stream.reset (); } void SAMSocket::Terminate (const char* reason) @@ -59,7 +58,11 @@ namespace client ; } m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket.is_open()) m_Socket.close (); + if (m_Socket.is_open ()) + { + m_Socket.shutdown (); + m_Socket.close (); + } m_Owner.RemoveSocket(this); } @@ -742,9 +745,11 @@ namespace client void SAMSocket::WriteI2PData(size_t sz) { - uint8_t * sendbuff = new uint8_t[sz]; - memcpy(sendbuff, m_StreamBuffer, sz); - WriteI2PDataImmediate(sendbuff, sz); + boost::asio::async_write ( + m_Socket, + boost::asio::buffer (m_StreamBuffer, sz), + boost::asio::transfer_all(), + std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1)); } void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -778,7 +783,8 @@ namespace client { WriteI2PData(bytes_transferred); } - I2PReceive(); + else + I2PReceive(); } } } @@ -897,7 +903,6 @@ namespace client SAMSession::~SAMSession () { - CloseStreams(); i2p::client::context.DeleteLocalDestination (localDestination); } From 5f525d0e4344bb5d062bb22be285d62aa58d4e52 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:16:15 -0400 Subject: [PATCH 034/115] fix previous commit --- libi2pd_client/SAM.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index b0ffda51..6511d8ba 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -60,7 +60,8 @@ namespace client m_SocketType = eSAMSocketTypeTerminated; if (m_Socket.is_open ()) { - m_Socket.shutdown (); + boost::system::error_code ec; + m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec); m_Socket.close (); } m_Owner.RemoveSocket(this); @@ -749,7 +750,7 @@ namespace client m_Socket, boost::asio::buffer (m_StreamBuffer, sz), boost::asio::transfer_all(), - std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1)); + std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) From 73b3fbc2daefc3258d3d1bd1c16f9fd17d528866 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:42:37 -0400 Subject: [PATCH 035/115] wrap m_OpenSockets with mutex --- libi2pd_client/SAM.cpp | 16 ++++++++++------ libi2pd_client/SAM.h | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 6511d8ba..0edc8252 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -33,7 +33,7 @@ namespace client if(m_Stream) { m_Stream->AsyncClose (); - m_Stream.reset (); + m_Stream = nullptr; } auto Session = m_Owner.FindSession(m_ID); switch (m_SocketType) @@ -64,7 +64,7 @@ namespace client m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec); m_Socket.close (); } - m_Owner.RemoveSocket(this); + m_Owner.RemoveSocket(shared_from_this()); } void SAMSocket::ReceiveHandshake () @@ -974,9 +974,10 @@ namespace client std::placeholders::_1, newSocket)); } - void SAMBridge::RemoveSocket(const SAMSocket * socket) + void SAMBridge::RemoveSocket(const std::shared_ptr & socket) { - m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item.get() == socket; }); + std::unique_lock lock(m_OpenSocketsMutex); + m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item == socket; }); } void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) @@ -988,7 +989,10 @@ namespace client if (!ec) { LogPrint (eLogDebug, "SAM: new connection from ", ep); - m_OpenSockets.push_back(socket); + { + std::unique_lock l(m_OpenSocketsMutex); + m_OpenSockets.push_back(socket); + } socket->ReceiveHandshake (); } else @@ -1074,7 +1078,7 @@ namespace client { std::list > list; { - std::unique_lock l(m_SessionsMutex); + std::unique_lock l(m_OpenSocketsMutex); for (const auto & itr : m_OpenSockets) if (itr->IsSession(id)) list.push_back(itr); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index d14e5e39..23cdf170 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -182,7 +182,7 @@ namespace client /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); - void RemoveSocket(const SAMSocket * socket); + void RemoveSocket(const std::shared_ptr & socket); private: @@ -204,6 +204,7 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; + mutable std::mutex m_OpenSocketsMutex; std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; From 623433099b2bd8456adad3f40abeda4ce8dee26d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:50:51 -0400 Subject: [PATCH 036/115] don't use reset --- libi2pd_client/SAM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 0edc8252..41db644d 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -25,7 +25,7 @@ namespace client SAMSocket::~SAMSocket () { - m_Stream.reset (); + m_Stream = nullptr; } void SAMSocket::Terminate (const char* reason) From 1e1e4da14471b190be0997b9be3948183fb7fbd7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 14:02:48 -0400 Subject: [PATCH 037/115] delete buffer --- libi2pd_client/SAM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 41db644d..d228e317 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -725,7 +725,10 @@ namespace client WriteI2PDataImmediate(buff, len); } else // no more data + { + delete [] buff; Terminate ("no more data"); + } } } } From 66de7ad0491264f4a0c179dac7e46dfbbd7ce7a1 Mon Sep 17 00:00:00 2001 From: Arm64 plaz Date: Tue, 24 Apr 2018 18:23:40 +0000 Subject: [PATCH 038/115] for first time disable aesenc for arm64 --- Makefile.linux | 7 ++++++- libi2pd/Crypto.cpp | 7 +++++++ libi2pd/Crypto.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Makefile.linux b/Makefile.linux index 4a82591a..2c30bbb0 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -60,7 +60,12 @@ endif ifeq ($(USE_AESNI),yes) #check if AES-NI is supported by CPU ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) - CPU_FLAGS += -maes -DAESNI + machine := $(shell uname -m) + ifeq ($(machine), aarch64) + CXXFLAGS += -DARM64AES + else + CPU_FLAGS += -maes -DAESNI + endif endif endif diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 5ba3334d..b0473410 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -594,6 +594,13 @@ namespace crypto // AES #ifdef AESNI + #ifdef ARM64AES + void init_aesenc(void) __attribute__((constructor)){ + + } + + #endif + #define KeyExpansion256(round0,round1) \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \ "movaps %%xmm1, %%xmm4 \n" \ diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 6e4ddb3d..859f2d97 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -124,6 +124,9 @@ namespace crypto #ifdef AESNI + #ifdef ARM64AES + void init_aesenc(void) __attribute__((constructor)); + #endif class ECBCryptoAESNI { public: From 97127e86dc1d600f667f7c0c0b205371f74eb8a0 Mon Sep 17 00:00:00 2001 From: Sammael <36346388+borned-mind@users.noreply.github.com> Date: Wed, 25 Apr 2018 01:59:11 +0700 Subject: [PATCH 039/115] Delete some for correct compilation --- libi2pd/Crypto.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index b0473410..8ba99a15 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -595,8 +595,8 @@ namespace crypto // AES #ifdef AESNI #ifdef ARM64AES - void init_aesenc(void) __attribute__((constructor)){ - + void init_aesenc(void){ + // TODO: Implementation } #endif From 72252318142076f5ed0486ee12dc6737ccfa3fd2 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Wed, 25 Apr 2018 16:15:40 +0800 Subject: [PATCH 040/115] perfecting qt status page --- daemon/HTTPServer.cpp | 43 ++- daemon/HTTPServer.h | 3 +- qt/i2pd_qt/i2pd_qt.pro | 618 +++++++++++++++++++------------------- qt/i2pd_qt/mainwindow.cpp | 4 +- 4 files changed, 342 insertions(+), 326 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 6f884a9b..12edf276 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -198,7 +198,10 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - void ShowStatus (std::stringstream& s, bool includeHiddenContent) + void ShowStatus ( + std::stringstream& s, + bool includeHiddenContent, + i2p::http::OutputFormatEnum outputFormat) { s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); @@ -245,9 +248,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 << "

\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" ; @@ -272,9 +278,12 @@ namespace http { } s << address->host.to_string() << ":" << address->port << "
\r\n"; } - } + } s << "

\r\n
\r\n"; - 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"; @@ -285,15 +294,17 @@ namespace http { s << "Client Tunnels: " << std::to_string(clientTunnelCount) << " "; s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n
\r\n"; - 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) @@ -863,7 +874,7 @@ namespace http { } else if (req.uri.find("cmd=") != std::string::npos) { HandleCommand (req, res, s); } else { - ShowStatus (s, true); + ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole); res.add_header("Refresh", "10"); } ShowPageTail (s); diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index 46477dae..a1b82875 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -80,7 +80,8 @@ namespace http }; //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml - void ShowStatus (std::stringstream& s, bool includeHiddenContent); + enum OutputFormatEnum { forWebConsole, forQtUi }; + void ShowStatus (std::stringstream& s, bool includeHiddenContent, OutputFormatEnum outputFormat); void ShowLocalDestinations (std::stringstream& s); void ShowLeasesSets(std::stringstream& s); void ShowTunnels (std::stringstream& s); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 21ef6358..12d13a17 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -1,308 +1,310 @@ -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = i2pd_qt -TEMPLATE = app -QMAKE_CXXFLAGS *= -std=c++11 -DEFINES += USE_UPNP - -# change to your own path, where you will store all needed libraries with 'git clone' commands below. -MAIN_PATH = /path/to/libraries - -# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -# 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 -BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt -OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt -MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt -IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs - -# Steps in Android SDK manager: -# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html -# 2) Check API 11 -# Finally, click Install. - -SOURCES += DaemonQT.cpp mainwindow.cpp \ - ../../libi2pd/api.cpp \ - ../../libi2pd/Base.cpp \ - ../../libi2pd/BloomFilter.cpp \ - ../../libi2pd/Config.cpp \ - ../../libi2pd/CPU.cpp \ - ../../libi2pd/Crypto.cpp \ - ../../libi2pd/CryptoKey.cpp \ - ../../libi2pd/Datagram.cpp \ - ../../libi2pd/Destination.cpp \ - ../../libi2pd/Event.cpp \ - ../../libi2pd/Family.cpp \ - ../../libi2pd/FS.cpp \ - ../../libi2pd/Garlic.cpp \ - ../../libi2pd/Gost.cpp \ - ../../libi2pd/Gzip.cpp \ - ../../libi2pd/HTTP.cpp \ - ../../libi2pd/I2NPProtocol.cpp \ - ../../libi2pd/I2PEndian.cpp \ - ../../libi2pd/Identity.cpp \ - ../../libi2pd/LeaseSet.cpp \ - ../../libi2pd/Log.cpp \ - ../../libi2pd/NetDb.cpp \ - ../../libi2pd/NetDbRequests.cpp \ - ../../libi2pd/NTCPSession.cpp \ - ../../libi2pd/Profiling.cpp \ - ../../libi2pd/Reseed.cpp \ - ../../libi2pd/RouterContext.cpp \ - ../../libi2pd/RouterInfo.cpp \ - ../../libi2pd/Signature.cpp \ - ../../libi2pd/SSU.cpp \ - ../../libi2pd/SSUData.cpp \ - ../../libi2pd/SSUSession.cpp \ - ../../libi2pd/Streaming.cpp \ - ../../libi2pd/Timestamp.cpp \ - ../../libi2pd/TransitTunnel.cpp \ - ../../libi2pd/Transports.cpp \ - ../../libi2pd/Tunnel.cpp \ - ../../libi2pd/TunnelEndpoint.cpp \ - ../../libi2pd/TunnelGateway.cpp \ - ../../libi2pd/TunnelPool.cpp \ - ../../libi2pd/util.cpp \ - ../../libi2pd_client/AddressBook.cpp \ - ../../libi2pd_client/BOB.cpp \ - ../../libi2pd_client/ClientContext.cpp \ - ../../libi2pd_client/HTTPProxy.cpp \ - ../../libi2pd_client/I2CP.cpp \ - ../../libi2pd_client/I2PService.cpp \ - ../../libi2pd_client/I2PTunnel.cpp \ - ../../libi2pd_client/MatchedDestination.cpp \ - ../../libi2pd_client/SAM.cpp \ - ../../libi2pd_client/SOCKS.cpp \ - ../../libi2pd_client/Websocket.cpp \ - ../../libi2pd_client/WebSocks.cpp \ - ClientTunnelPane.cpp \ - MainWindowItems.cpp \ - ServerTunnelPane.cpp \ - SignatureTypeComboboxFactory.cpp \ - TunnelConfig.cpp \ - TunnelPane.cpp \ - ../../daemon/Daemon.cpp \ - ../../daemon/HTTPServer.cpp \ - ../../daemon/i2pd.cpp \ - ../../daemon/I2PControl.cpp \ - ../../daemon/UnixDaemon.cpp \ - ../../daemon/UPnP.cpp \ - textbrowsertweaked1.cpp \ - pagewithbackbutton.cpp \ - widgetlock.cpp \ - widgetlockregistry.cpp - -#qt creator does not handle this well -#SOURCES += $$files(../../libi2pd/*.cpp) -#SOURCES += $$files(../../libi2pd_client/*.cpp) -#SOURCES += $$files(../../daemon/*.cpp) -#SOURCES += $$files(./*.cpp) - -SOURCES -= ../../daemon/UnixDaemon.cpp - -HEADERS += DaemonQT.h mainwindow.h \ - ../../libi2pd/api.h \ - ../../libi2pd/Base.h \ - ../../libi2pd/BloomFilter.h \ - ../../libi2pd/Config.h \ - ../../libi2pd/Crypto.h \ - ../../libi2pd/CryptoKey.h \ - ../../libi2pd/Datagram.h \ - ../../libi2pd/Destination.h \ - ../../libi2pd/Event.h \ - ../../libi2pd/Family.h \ - ../../libi2pd/FS.h \ - ../../libi2pd/Garlic.h \ - ../../libi2pd/Gost.h \ - ../../libi2pd/Gzip.h \ - ../../libi2pd/HTTP.h \ - ../../libi2pd/I2NPProtocol.h \ - ../../libi2pd/I2PEndian.h \ - ../../libi2pd/Identity.h \ - ../../libi2pd/LeaseSet.h \ - ../../libi2pd/LittleBigEndian.h \ - ../../libi2pd/Log.h \ - ../../libi2pd/NetDb.hpp \ - ../../libi2pd/NetDbRequests.h \ - ../../libi2pd/NTCPSession.h \ - ../../libi2pd/Profiling.h \ - ../../libi2pd/Queue.h \ - ../../libi2pd/Reseed.h \ - ../../libi2pd/RouterContext.h \ - ../../libi2pd/RouterInfo.h \ - ../../libi2pd/Signature.h \ - ../../libi2pd/SSU.h \ - ../../libi2pd/SSUData.h \ - ../../libi2pd/SSUSession.h \ - ../../libi2pd/Streaming.h \ - ../../libi2pd/Tag.h \ - ../../libi2pd/Timestamp.h \ - ../../libi2pd/TransitTunnel.h \ - ../../libi2pd/Transports.h \ - ../../libi2pd/TransportSession.h \ - ../../libi2pd/Tunnel.h \ - ../../libi2pd/TunnelBase.h \ - ../../libi2pd/TunnelConfig.h \ - ../../libi2pd/TunnelEndpoint.h \ - ../../libi2pd/TunnelGateway.h \ - ../../libi2pd/TunnelPool.h \ - ../../libi2pd/util.h \ - ../../libi2pd/version.h \ - ../../libi2pd_client/AddressBook.h \ - ../../libi2pd_client/BOB.h \ - ../../libi2pd_client/ClientContext.h \ - ../../libi2pd_client/HTTPProxy.h \ - ../../libi2pd_client/I2CP.h \ - ../../libi2pd_client/I2PService.h \ - ../../libi2pd_client/I2PTunnel.h \ - ../../libi2pd_client/MatchedDestination.h \ - ../../libi2pd_client/SAM.h \ - ../../libi2pd_client/SOCKS.h \ - ../../libi2pd_client/Websocket.h \ - ../../libi2pd_client/WebSocks.h \ - ClientTunnelPane.h \ - MainWindowItems.h \ - ServerTunnelPane.h \ - SignatureTypeComboboxFactory.h \ - TunnelConfig.h \ - TunnelPane.h \ - TunnelsPageUpdateListener.h \ - ../../daemon/Daemon.h \ - ../../daemon/HTTPServer.h \ - ../../daemon/I2PControl.h \ - ../../daemon/UPnP.h \ - textbrowsertweaked1.h \ - pagewithbackbutton.h \ - widgetlock.h \ - widgetlockregistry.h - -INCLUDEPATH += ../../libi2pd -INCLUDEPATH += ../../libi2pd_client -INCLUDEPATH += ../../daemon -INCLUDEPATH += . - -FORMS += mainwindow.ui \ - tunnelform.ui \ - statusbuttons.ui \ - routercommandswidget.ui \ - generalsettingswidget.ui - -LIBS += -lz - -macx { - message("using mac os x target") - BREWROOT=/usr/local - BOOSTROOT=$$BREWROOT/opt/boost - SSLROOT=$$BREWROOT/opt/libressl - UPNPROOT=$$BREWROOT/opt/miniupnpc - INCLUDEPATH += $$BOOSTROOT/include - INCLUDEPATH += $$SSLROOT/include - INCLUDEPATH += $$UPNPROOT/include - LIBS += $$SSLROOT/lib/libcrypto.a - LIBS += $$SSLROOT/lib/libssl.a - LIBS += $$BOOSTROOT/lib/libboost_system.a - LIBS += $$BOOSTROOT/lib/libboost_date_time.a - LIBS += $$BOOSTROOT/lib/libboost_filesystem.a - LIBS += $$BOOSTROOT/lib/libboost_program_options.a - LIBS += $$UPNPROOT/lib/libminiupnpc.a -} - -android { - message("Using Android settings") - DEFINES += ANDROID=1 - DEFINES += __ANDROID__ - - CONFIG += mobility - - MOBILITY = - - INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ - $$OPENSSL_PATH/openssl-1.0.2/include \ - $$MINIUPNP_PATH/miniupnp-2.0/include \ - $$IFADDRS_PATH - DISTFILES += android/AndroidManifest.xml - - ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android - - SOURCES += $$IFADDRS_PATH/ifaddrs.c - HEADERS += $$IFADDRS_PATH/ifaddrs.h - - equals(ANDROID_TARGET_ARCH, armeabi-v7a){ - DEFINES += ANDROID_ARM7A - # http://stackoverflow.com/a/30235934/529442 - LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ - -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ - -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ - -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \ - -L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc - - PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ - $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a - DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include - - ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \ - $$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so - } - - equals(ANDROID_TARGET_ARCH, x86){ - # http://stackoverflow.com/a/30235934/529442 - LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ - -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ - -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ - -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \ - -L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc - - PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ - $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a - - DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include - - ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \ - $$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so - } -} - -linux:!android { - message("Using Linux settings") - LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc -} - -windows { - message("Using Windows settings") - RC_FILE = i2pd.rc - DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB - DEFINES -= UNICODE _UNICODE - BOOST_SUFFIX = -mt - QMAKE_CXXFLAGS = -Os - QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows - - LIBS = -lminiupnpc \ - -lboost_system$$BOOST_SUFFIX \ - -lboost_date_time$$BOOST_SUFFIX \ - -lboost_filesystem$$BOOST_SUFFIX \ - -lboost_program_options$$BOOST_SUFFIX \ - -lssl \ - -lcrypto \ - -lz \ - -lwsock32 \ - -lws2_32 \ - -lgdi32 \ - -liphlpapi \ - -lstdc++ \ - -lpthread -} - -!android:!symbian:!maemo5:!simulator { - message("Build with a system tray icon") - # see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince* - #sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images - RESOURCES = i2pd.qrc - QT += xml - #INSTALLS += sources -} - +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = i2pd_qt +TEMPLATE = app +QMAKE_CXXFLAGS *= -std=c++11 +DEFINES += USE_UPNP + +# change to your own path, where you will store all needed libraries with 'git clone' commands below. +MAIN_PATH = /path/to/libraries + +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# 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 +BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt +OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs + +# Steps in Android SDK manager: +# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html +# 2) Check API 11 +# Finally, click Install. + +SOURCES += DaemonQT.cpp mainwindow.cpp \ + ../../libi2pd/api.cpp \ + ../../libi2pd/Base.cpp \ + ../../libi2pd/BloomFilter.cpp \ + ../../libi2pd/Config.cpp \ + ../../libi2pd/CPU.cpp \ + ../../libi2pd/Crypto.cpp \ + ../../libi2pd/CryptoKey.cpp \ + ../../libi2pd/Datagram.cpp \ + ../../libi2pd/Destination.cpp \ + ../../libi2pd/Event.cpp \ + ../../libi2pd/Family.cpp \ + ../../libi2pd/FS.cpp \ + ../../libi2pd/Garlic.cpp \ + ../../libi2pd/Gost.cpp \ + ../../libi2pd/Gzip.cpp \ + ../../libi2pd/HTTP.cpp \ + ../../libi2pd/I2NPProtocol.cpp \ + ../../libi2pd/I2PEndian.cpp \ + ../../libi2pd/Identity.cpp \ + ../../libi2pd/LeaseSet.cpp \ + ../../libi2pd/Log.cpp \ + ../../libi2pd/NetDb.cpp \ + ../../libi2pd/NetDbRequests.cpp \ + ../../libi2pd/NTCPSession.cpp \ + ../../libi2pd/Profiling.cpp \ + ../../libi2pd/Reseed.cpp \ + ../../libi2pd/RouterContext.cpp \ + ../../libi2pd/RouterInfo.cpp \ + ../../libi2pd/Signature.cpp \ + ../../libi2pd/SSU.cpp \ + ../../libi2pd/SSUData.cpp \ + ../../libi2pd/SSUSession.cpp \ + ../../libi2pd/Streaming.cpp \ + ../../libi2pd/Timestamp.cpp \ + ../../libi2pd/TransitTunnel.cpp \ + ../../libi2pd/Transports.cpp \ + ../../libi2pd/Tunnel.cpp \ + ../../libi2pd/TunnelEndpoint.cpp \ + ../../libi2pd/TunnelGateway.cpp \ + ../../libi2pd/TunnelPool.cpp \ + ../../libi2pd/util.cpp \ + ../../libi2pd_client/AddressBook.cpp \ + ../../libi2pd_client/BOB.cpp \ + ../../libi2pd_client/ClientContext.cpp \ + ../../libi2pd_client/HTTPProxy.cpp \ + ../../libi2pd_client/I2CP.cpp \ + ../../libi2pd_client/I2PService.cpp \ + ../../libi2pd_client/I2PTunnel.cpp \ + ../../libi2pd_client/MatchedDestination.cpp \ + ../../libi2pd_client/SAM.cpp \ + ../../libi2pd_client/SOCKS.cpp \ + ../../libi2pd_client/Websocket.cpp \ + ../../libi2pd_client/WebSocks.cpp \ + ClientTunnelPane.cpp \ + MainWindowItems.cpp \ + ServerTunnelPane.cpp \ + SignatureTypeComboboxFactory.cpp \ + TunnelConfig.cpp \ + TunnelPane.cpp \ + ../../daemon/Daemon.cpp \ + ../../daemon/HTTPServer.cpp \ + ../../daemon/i2pd.cpp \ + ../../daemon/I2PControl.cpp \ + ../../daemon/UnixDaemon.cpp \ + ../../daemon/UPnP.cpp \ + textbrowsertweaked1.cpp \ + pagewithbackbutton.cpp \ + widgetlock.cpp \ + widgetlockregistry.cpp + +#qt creator does not handle this well +#SOURCES += $$files(../../libi2pd/*.cpp) +#SOURCES += $$files(../../libi2pd_client/*.cpp) +#SOURCES += $$files(../../daemon/*.cpp) +#SOURCES += $$files(./*.cpp) + +SOURCES -= ../../daemon/UnixDaemon.cpp + +HEADERS += DaemonQT.h mainwindow.h \ + ../../libi2pd/api.h \ + ../../libi2pd/Base.h \ + ../../libi2pd/BloomFilter.h \ + ../../libi2pd/Config.h \ + ../../libi2pd/Crypto.h \ + ../../libi2pd/CryptoKey.h \ + ../../libi2pd/Datagram.h \ + ../../libi2pd/Destination.h \ + ../../libi2pd/Event.h \ + ../../libi2pd/Family.h \ + ../../libi2pd/FS.h \ + ../../libi2pd/Garlic.h \ + ../../libi2pd/Gost.h \ + ../../libi2pd/Gzip.h \ + ../../libi2pd/HTTP.h \ + ../../libi2pd/I2NPProtocol.h \ + ../../libi2pd/I2PEndian.h \ + ../../libi2pd/Identity.h \ + ../../libi2pd/LeaseSet.h \ + ../../libi2pd/LittleBigEndian.h \ + ../../libi2pd/Log.h \ + ../../libi2pd/NetDb.hpp \ + ../../libi2pd/NetDbRequests.h \ + ../../libi2pd/NTCPSession.h \ + ../../libi2pd/Profiling.h \ + ../../libi2pd/Queue.h \ + ../../libi2pd/Reseed.h \ + ../../libi2pd/RouterContext.h \ + ../../libi2pd/RouterInfo.h \ + ../../libi2pd/Signature.h \ + ../../libi2pd/SSU.h \ + ../../libi2pd/SSUData.h \ + ../../libi2pd/SSUSession.h \ + ../../libi2pd/Streaming.h \ + ../../libi2pd/Tag.h \ + ../../libi2pd/Timestamp.h \ + ../../libi2pd/TransitTunnel.h \ + ../../libi2pd/Transports.h \ + ../../libi2pd/TransportSession.h \ + ../../libi2pd/Tunnel.h \ + ../../libi2pd/TunnelBase.h \ + ../../libi2pd/TunnelConfig.h \ + ../../libi2pd/TunnelEndpoint.h \ + ../../libi2pd/TunnelGateway.h \ + ../../libi2pd/TunnelPool.h \ + ../../libi2pd/util.h \ + ../../libi2pd/version.h \ + ../../libi2pd_client/AddressBook.h \ + ../../libi2pd_client/BOB.h \ + ../../libi2pd_client/ClientContext.h \ + ../../libi2pd_client/HTTPProxy.h \ + ../../libi2pd_client/I2CP.h \ + ../../libi2pd_client/I2PService.h \ + ../../libi2pd_client/I2PTunnel.h \ + ../../libi2pd_client/MatchedDestination.h \ + ../../libi2pd_client/SAM.h \ + ../../libi2pd_client/SOCKS.h \ + ../../libi2pd_client/Websocket.h \ + ../../libi2pd_client/WebSocks.h \ + ClientTunnelPane.h \ + MainWindowItems.h \ + ServerTunnelPane.h \ + SignatureTypeComboboxFactory.h \ + TunnelConfig.h \ + TunnelPane.h \ + TunnelsPageUpdateListener.h \ + ../../daemon/Daemon.h \ + ../../daemon/HTTPServer.h \ + ../../daemon/I2PControl.h \ + ../../daemon/UPnP.h \ + textbrowsertweaked1.h \ + pagewithbackbutton.h \ + widgetlock.h \ + widgetlockregistry.h \ + i2pd.rc \ + i2pd.rc + +INCLUDEPATH += ../../libi2pd +INCLUDEPATH += ../../libi2pd_client +INCLUDEPATH += ../../daemon +INCLUDEPATH += . + +FORMS += mainwindow.ui \ + tunnelform.ui \ + statusbuttons.ui \ + routercommandswidget.ui \ + generalsettingswidget.ui + +LIBS += -lz + +macx { + message("using mac os x target") + BREWROOT=/usr/local + BOOSTROOT=$$BREWROOT/opt/boost + SSLROOT=$$BREWROOT/opt/libressl + UPNPROOT=$$BREWROOT/opt/miniupnpc + INCLUDEPATH += $$BOOSTROOT/include + INCLUDEPATH += $$SSLROOT/include + INCLUDEPATH += $$UPNPROOT/include + LIBS += $$SSLROOT/lib/libcrypto.a + LIBS += $$SSLROOT/lib/libssl.a + LIBS += $$BOOSTROOT/lib/libboost_system.a + LIBS += $$BOOSTROOT/lib/libboost_date_time.a + LIBS += $$BOOSTROOT/lib/libboost_filesystem.a + LIBS += $$BOOSTROOT/lib/libboost_program_options.a + LIBS += $$UPNPROOT/lib/libminiupnpc.a +} + +android { + message("Using Android settings") + DEFINES += ANDROID=1 + DEFINES += __ANDROID__ + + CONFIG += mobility + + MOBILITY = + + INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ + $$OPENSSL_PATH/openssl-1.0.2/include \ + $$MINIUPNP_PATH/miniupnp-2.0/include \ + $$IFADDRS_PATH + DISTFILES += android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android + + SOURCES += $$IFADDRS_PATH/ifaddrs.c + HEADERS += $$IFADDRS_PATH/ifaddrs.h + + equals(ANDROID_TARGET_ARCH, armeabi-v7a){ + DEFINES += ANDROID_ARM7A + # http://stackoverflow.com/a/30235934/529442 + LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ + -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ + -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ + -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \ + -L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc + + PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ + $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a + DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include + + ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ + $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so + } + + equals(ANDROID_TARGET_ARCH, x86){ + # http://stackoverflow.com/a/30235934/529442 + LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ + -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ + -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ + -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \ + -L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc + + PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ + $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a + + DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include + + ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ + $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so + } +} + +linux:!android { + message("Using Linux settings") + LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc +} + +windows { + message("Using Windows settings") + RC_FILE = i2pd.rc + DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB + DEFINES -= UNICODE _UNICODE + BOOST_SUFFIX = -mt + QMAKE_CXXFLAGS = -Os + QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + LIBS = -lminiupnpc \ + -lboost_system$$BOOST_SUFFIX \ + -lboost_date_time$$BOOST_SUFFIX \ + -lboost_filesystem$$BOOST_SUFFIX \ + -lboost_program_options$$BOOST_SUFFIX \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread +} + +!android:!symbian:!maemo5:!simulator { + message("Build with a system tray icon") + # see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince* + #sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images + RESOURCES = i2pd.qrc + QT += xml + #INSTALLS += sources +} + diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index c3761764..a095f78c 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -349,7 +349,9 @@ QString MainWindow::getStatusPageHtml(bool showHiddenInfo) { s << ""; switch (statusPage) { - case main_page: i2p::http::ShowStatus(s, showHiddenInfo);break; + case main_page: + i2p::http::ShowStatus(s, showHiddenInfo, i2p::http::OutputFormatEnum::forQtUi); + break; case commands: break; case local_destinations: i2p::http::ShowLocalDestinations(s);break; case leasesets: i2p::http::ShowLeasesSets(s); break; From b046c45a9e7db86906684441818cc7153f269314 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 25 Apr 2018 11:25:49 -0400 Subject: [PATCH 041/115] tabify --- libi2pd_client/SAM.cpp | 6 +++--- libi2pd_client/SAM.h | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index d228e317..ac2dd853 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -207,7 +207,7 @@ namespace client void SAMSocket::HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close) { if (ecode) - { + { LogPrint (eLogError, "SAM: reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: reply send error"); @@ -224,7 +224,7 @@ namespace client void SAMSocket::HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: read error"); @@ -569,7 +569,7 @@ namespace client keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #else size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, - keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); + keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #endif SendMessageReply (m_Buffer, l, false); } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 23cdf170..0c70758f 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -92,12 +92,12 @@ namespace client void Terminate (const char* reason); - bool IsSession(const std::string & id) const; - + bool IsSession(const std::string & id) const; + private: - void TerminateClose() { Terminate(nullptr); } - - void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void TerminateClose() { Terminate(nullptr); } + + void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendMessageReply (const char * msg, size_t len, bool close); @@ -131,8 +131,8 @@ namespace client void WriteI2PDataImmediate(uint8_t * ptr, size_t sz); void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff); - void HandleStreamSend(const boost::system::error_code & ec); - + void HandleStreamSend(const boost::system::error_code & ec); + private: SAMBridge& m_Owner; @@ -150,10 +150,10 @@ namespace client struct SAMSession { - SAMBridge & m_Bridge; + SAMBridge & m_Bridge; std::shared_ptr localDestination; std::shared_ptr UDPEndpoint; - std::string Name; + std::string Name; SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); ~SAMSession (); @@ -172,24 +172,24 @@ namespace client void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient + std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; - std::list > ListSockets(const std::string & id) const; + std::list > ListSockets(const std::string & id) const; /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); - void RemoveSocket(const std::shared_ptr & socket); - + void RemoveSocket(const std::shared_ptr & socket); + private: void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); void ReceiveDatagram (); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -204,8 +204,8 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; - mutable std::mutex m_OpenSocketsMutex; - std::list > m_OpenSockets; + mutable std::mutex m_OpenSocketsMutex; + std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; public: From 0ced38cdcbcae6f6bfe1ab653d85f201f194c247 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 25 Apr 2018 11:27:56 -0400 Subject: [PATCH 042/115] tabify --- libi2pd/Streaming.h | 4 ++-- libi2pd_client/SAM.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 7f2598c0..3db8d760 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -165,9 +165,9 @@ namespace stream void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; - void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; + void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; - /** only call close from destination thread, use Stream::AsyncClose for other threads */ + /** only call close from destination thread, use Stream::AsyncClose for other threads */ void Close (); void Cancel () { m_ReceiveTimer.cancel (); }; diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 0c70758f..953af1cd 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -77,7 +77,7 @@ namespace client class SAMBridge; struct SAMSession; - class SAMSocket :public std::enable_shared_from_this + class SAMSocket: public std::enable_shared_from_this { public: From 2fbbbf298bf272009618332bed2d2e58977fdc21 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 Apr 2018 16:18:07 -0400 Subject: [PATCH 043/115] use shared pointers for tunnel reload --- libi2pd_client/ClientContext.cpp | 54 +++++++++++++++++--------------- libi2pd_client/ClientContext.h | 8 ++--- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 6c3a9410..99f34b73 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -488,8 +488,8 @@ namespace client { localDestination = m_SharedLocalDestination; } - auto clientTunnel = new I2PUDPClientTunnel(name, dest, end, localDestination, destinationPort); - if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr(clientTunnel))).second) + auto clientTunnel = std::make_shared(name, dest, end, localDestination, destinationPort); + if(m_ClientForwards.insert(std::make_pair(end, clientTunnel)).second) { clientTunnel->Start(); } @@ -498,31 +498,35 @@ namespace client } else { boost::asio::ip::tcp::endpoint clientEndpoint; - I2PService * clientTunnel = nullptr; + std::shared_ptr clientTunnel; if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS) { // socks proxy - clientTunnel = new i2p::proxy::SOCKSProxy(name, address, port, false, "", destinationPort, localDestination); - clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared(name, address, port, false, "", destinationPort, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) { // http proxy std::string outproxy = section.second.get("outproxy", ""); - clientTunnel = new i2p::proxy::HTTPProxy(name, address, port, outproxy, localDestination); - clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared(name, address, port, outproxy, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) { // websocks proxy - clientTunnel = new WebSocks(address, port, localDestination);; - clientEndpoint = ((WebSocks*)clientTunnel)->GetLocalEndpoint(); + auto tun = std::make_shared(address, port, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint(); } else { // tcp client - clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); - clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared (name, dest, address, port, localDestination, destinationPort); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } uint32_t timeout = section.second.get(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0); if(timeout) @@ -531,8 +535,7 @@ namespace client LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); } - auto clientTunnelDest = clientTunnel->GetLocalDestination (); // make copy of destination for possible update - auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))); + auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel)); if (ins.second) { clientTunnel->Start (); @@ -541,10 +544,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != clientTunnelDest) + if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) { LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); - ins.first->second->SetLocalDestination (clientTunnelDest); + ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); @@ -589,7 +592,7 @@ namespace client // TODO: hostnames auto localAddress = boost::asio::ip::address::from_string(address); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); - I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port); + auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, port); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); @@ -600,7 +603,7 @@ namespace client std::make_pair( std::make_pair( localDestination->GetIdentHash(), port), - std::unique_ptr(serverTunnel))).second) + serverTunnel)).second) { serverTunnel->Start(); LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32()); @@ -611,13 +614,13 @@ namespace client continue; } - I2PServerTunnel * serverTunnel; + std::shared_ptr serverTunnel; if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) - serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, hostOverride, inPort, gzip); else if (type == I2P_TUNNELS_SECTION_TYPE_IRC) - serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, webircpass, inPort, gzip); else // regular server tunnel by default - serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, inPort, gzip); if(!isUniqueLocal) { @@ -640,10 +643,9 @@ namespace client while (comma != std::string::npos); serverTunnel->SetAccessList (idents); } - auto serverTunnelDest = serverTunnel->GetLocalDestination (); auto ins = m_ServerTunnels.insert (std::make_pair ( - std::make_pair (localDestination->GetIdentHash (), inPort), - std::unique_ptr(serverTunnel))); + std::make_pair (localDestination->GetIdentHash (), inPort), + serverTunnel)); if (ins.second) { serverTunnel->Start (); @@ -652,10 +654,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != serverTunnelDest) + if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) { LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); - ins.first->second->SetLocalDestination (serverTunnelDest); + ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 922d7acc..06aab3b1 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -113,12 +113,12 @@ namespace client i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::SOCKSProxy * m_SocksProxy; - std::map > m_ClientTunnels; // local endpoint->tunnel - std::map, std::unique_ptr > m_ServerTunnels; // ->tunnel + std::map > m_ClientTunnels; // local endpoint->tunnel + std::map, std::shared_ptr > m_ServerTunnels; // ->tunnel std::mutex m_ForwardsMutex; - std::map > m_ClientForwards; // local endpoint -> udp tunnel - std::map, std::unique_ptr > m_ServerForwards; // -> udp tunnel + std::map > m_ClientForwards; // local endpoint -> udp tunnel + std::map, std::shared_ptr > m_ServerForwards; // -> udp tunnel SAMBridge * m_SamBridge; BOBCommandChannel * m_BOBCommandChannel; From ad23ccb2191c8478da2ade1f565d32c6b70f9e39 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:28:30 +0300 Subject: [PATCH 044/115] separating android binary build --- {android/i2pd => android_binary/jni}/Android.mk | 2 +- {android/i2pd => android_binary/jni}/Application.mk | 2 +- daemon/Daemon.h | 2 +- daemon/HTTPServer.cpp | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) rename {android/i2pd => android_binary/jni}/Android.mk (98%) rename {android/i2pd => android_binary/jni}/Application.mk (95%) diff --git a/android/i2pd/Android.mk b/android_binary/jni/Android.mk similarity index 98% rename from android/i2pd/Android.mk rename to android_binary/jni/Android.mk index ae56110c..1c7cd92e 100755 --- a/android/i2pd/Android.mk +++ b/android_binary/jni/Android.mk @@ -13,7 +13,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS := -lz LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ - $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ $(DAEMON_SRC_PATH)/Daemon.cpp \ diff --git a/android/i2pd/Application.mk b/android_binary/jni/Application.mk similarity index 95% rename from android/i2pd/Application.mk rename to android_binary/jni/Application.mk index acc6f895..c2112d54 100755 --- a/android/i2pd/Application.mk +++ b/android_binary/jni/Application.mk @@ -15,7 +15,7 @@ APP_STL := gnustl_static # Enable c++11 extensions in source code APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE -APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 4491d303..00baf7b9 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -64,7 +64,7 @@ namespace util DaemonWin32 ():isGraceful(false) {} }; -#elif defined(ANDROID) +#elif (defined(ANDROID) && !defined(ANDROID_BINARY)) #define Daemon i2p::util::DaemonAndroid::Instance() // dummy, invoked from android/jni/DaemonAndroid.* class DaemonAndroid: public i2p::util::Daemon_Singleton diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 657e6d43..faf386d8 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -227,7 +227,7 @@ namespace http { default: s << "Unknown"; } s << "
\r\n"; -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (auto remains = Daemon.gracefulShutdownInterval) { s << "Stopping in: "; s << remains << " seconds"; @@ -504,7 +504,7 @@ namespace http { s << " Decline transit tunnels
\r\n"; else s << " Accept transit tunnels
\r\n"; -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (Daemon.gracefulShutdownInterval) s << " Cancel graceful shutdown
"; else @@ -964,14 +964,14 @@ namespace http { i2p::context.SetAcceptsTunnels (false); else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { i2p::context.SetAcceptsTunnels (false); -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#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) { i2p::context.SetAcceptsTunnels (true); -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) Daemon.gracefulShutdownInterval = 0; #elif defined(WIN32_APP) i2p::win32::StopGracefulShutdown (); From c7b796ff313d007f6bfd1e0ab4830234b4d8cbd6 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:40:13 +0300 Subject: [PATCH 045/115] separate Android binary build based on DaemonLinux --- {android_binary => android_binary_only}/jni/Android.mk | 0 {android_binary => android_binary_only}/jni/Application.mk | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {android_binary => android_binary_only}/jni/Android.mk (100%) rename {android_binary => android_binary_only}/jni/Application.mk (100%) diff --git a/android_binary/jni/Android.mk b/android_binary_only/jni/Android.mk similarity index 100% rename from android_binary/jni/Android.mk rename to android_binary_only/jni/Android.mk diff --git a/android_binary/jni/Application.mk b/android_binary_only/jni/Application.mk similarity index 100% rename from android_binary/jni/Application.mk rename to android_binary_only/jni/Application.mk From 08a8ab98926797a2b9d9e3af6d8ead289227b25c Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:42:12 +0300 Subject: [PATCH 046/115] format --- android_binary_only/jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android_binary_only/jni/Android.mk b/android_binary_only/jni/Android.mk index 1c7cd92e..ae56110c 100755 --- a/android_binary_only/jni/Android.mk +++ b/android_binary_only/jni/Android.mk @@ -13,7 +13,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS := -lz LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ - $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ $(DAEMON_SRC_PATH)/Daemon.cpp \ From 6e95318cba0ce810ce7e7a1c2e72b4882afbfff3 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:44:32 +0300 Subject: [PATCH 047/115] I2PD_LIBS_PATH = /path/to/libraries to be same as in android normal build --- android_binary_only/jni/Application.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android_binary_only/jni/Application.mk b/android_binary_only/jni/Application.mk index c2112d54..7cd5c813 100755 --- a/android_binary_only/jni/Application.mk +++ b/android_binary_only/jni/Application.mk @@ -28,7 +28,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +I2PD_LIBS_PATH = /path/to/libraries BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt From db8a546b8fa2d23accbdf41de3ddc69e66df10d7 Mon Sep 17 00:00:00 2001 From: Al Date: Thu, 26 Apr 2018 20:07:51 +0000 Subject: [PATCH 048/115] android i2pd executable build instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8fc8393a..9b7e42d4 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,12 @@ Build instructions: * [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/) * [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/) * [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/) +* android executable binary build: + - clone https://github.com/unlnown542a/i2pd.git or download https://github.com/unlnown542a/i2pd/archive/openssl.zip + - change to i2pd/android_binary_only + - edit jni/Application.mk - define path to static libs I2PD_LIBS_PATH + - in the directory i2pd/android_binary_only run: ndk-build -j4 + - find compiled binary - libs/armeabi-v7a/i2pd **Supported systems:** From 6265d452e9f464aebdd140429e87028d3705fb33 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 29 Apr 2018 10:53:04 -0400 Subject: [PATCH 049/115] more bounds checking --- libi2pd/Destination.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b7c2ee32..4e758c92 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); @@ -859,6 +859,11 @@ namespace client void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); + if(length > len - 4) + { + LogPrint(eLogError, "Destination: Data message length ", length, " exceeds buffer length ", len); + return; + } buf += 4; // we assume I2CP payload uint16_t fromPort = bufbe16toh (buf + 4), // source From a63bc1cdca9b338c3c672aee4c79399e8087617c Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 29 Apr 2018 11:41:03 -0400 Subject: [PATCH 050/115] correct sizes --- libi2pd/Destination.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4e758c92..e565d6c0 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); From db035954732dadc5f8a8f09c944159ba56592504 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Apr 2018 18:05:28 -0400 Subject: [PATCH 051/115] correct message size --- libi2pd/Destination.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e565d6c0..d3632881 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); From a22e9a2ca7f117daf6b17b11fb51e1549d87c621 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Apr 2018 13:34:16 -0400 Subject: [PATCH 052/115] don't start shared local destination twice --- libi2pd_client/ClientContext.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 99f34b73..b40c2832 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -362,8 +362,6 @@ namespace client { m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA m_SharedLocalDestination->Acquire (); - m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination; - m_SharedLocalDestination->Start (); } std::shared_ptr ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const From 53a1a097a61e7a59af10a1166546c8e1b9387445 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Fri, 18 May 2018 15:45:35 -0400 Subject: [PATCH 053/115] Restore reseed certificate hottuna_at_mail.i2p.crt --- .../reseed/hottuna_at_mail.i2p.crt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 contrib/certificates/reseed/hottuna_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/hottuna_at_mail.i2p.crt b/contrib/certificates/reseed/hottuna_at_mail.i2p.crt new file mode 100644 index 00000000..d0ff7c33 --- /dev/null +++ b/contrib/certificates/reseed/hottuna_at_mail.i2p.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- From d8b4765f23952ad6ae5c816cfd30ef88facd2d89 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Fri, 18 May 2018 15:54:39 -0400 Subject: [PATCH 054/115] Add /etc/resolv.conf to apparmor profile and k flag for pidfile --- contrib/apparmor/usr.sbin.i2pd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/apparmor/usr.sbin.i2pd b/contrib/apparmor/usr.sbin.i2pd index 4349e07b..168070da 100644 --- a/contrib/apparmor/usr.sbin.i2pd +++ b/contrib/apparmor/usr.sbin.i2pd @@ -17,14 +17,15 @@ /etc/host.conf r, /etc/hosts r, /etc/nsswitch.conf r, + /etc/resolv.conf r, /run/resolvconf/resolv.conf r, # path specific (feel free to modify if you have another paths) /etc/i2pd/** r, - /run/i2pd/i2pd.pid rw, + /run/i2pd/i2pd.pid rwk, /var/lib/i2pd/** rw, /var/log/i2pd/i2pd.log w, - /var/run/i2pd/i2pd.pid rw, + /var/run/i2pd/i2pd.pid rwk, /usr/sbin/i2pd mr, /usr/share/i2pd/** r, From 5ec11c53e9fd79aeace80512c50f584978bb22f2 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sun, 6 May 2018 12:26:59 +0800 Subject: [PATCH 055/115] differentiation between windows release and debug build into i2pd_qt.pro --- qt/i2pd_qt/i2pd_qt.pro | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 12d13a17..8ae9f581 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app -QMAKE_CXXFLAGS *= -std=c++11 +QMAKE_CXXFLAGS *= -std=c++11 -ggdb DEFINES += USE_UPNP # change to your own path, where you will store all needed libraries with 'git clone' commands below. @@ -280,8 +280,11 @@ windows { DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB DEFINES -= UNICODE _UNICODE BOOST_SUFFIX = -mt - QMAKE_CXXFLAGS = -Os - QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + QMAKE_CXXFLAGS_RELEASE = -Os + QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + #strip + QMAKE_LFLAGS_RELEASE += -s LIBS = -lminiupnpc \ -lboost_system$$BOOST_SUFFIX \ From f8fe124428df31cc7942417b9f4e74a31d1ecb14 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sun, 6 May 2018 12:30:09 +0800 Subject: [PATCH 056/115] improved comment at qt.pro file --- qt/i2pd_qt/i2pd_qt.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 8ae9f581..86cf579e 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -283,7 +283,7 @@ windows { QMAKE_CXXFLAGS_RELEASE = -Os QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows - #strip + #linker's -s means "strip" QMAKE_LFLAGS_RELEASE += -s LIBS = -lminiupnpc \ From ed2818eaa24dd7f0e883e05e97544986858db9af Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sat, 19 May 2018 23:03:49 +0800 Subject: [PATCH 057/115] qt log viewer now works --- daemon/Daemon.cpp | 13 ++- daemon/Daemon.h | 6 +- libi2pd/Log.cpp | 16 ++- qt/i2pd_qt/DaemonQT.cpp | 27 +++-- qt/i2pd_qt/DaemonQT.h | 2 +- qt/i2pd_qt/SignatureTypeComboboxFactory.h | 2 +- qt/i2pd_qt/i2pd_qt.pro | 6 +- qt/i2pd_qt/logviewermanager.cpp | 45 ++++++++ qt/i2pd_qt/logviewermanager.h | 130 ++++++++++++++++++++++ qt/i2pd_qt/mainwindow.cpp | 24 +++- qt/i2pd_qt/mainwindow.h | 24 ++-- qt/i2pd_qt/mainwindow.ui | 80 ++++++++++++- 12 files changed, 335 insertions(+), 40 deletions(-) create mode 100644 qt/i2pd_qt/logviewermanager.cpp create mode 100644 qt/i2pd_qt/logviewermanager.h diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index d077644d..ee56a1c7 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -60,8 +60,12 @@ namespace i2p return service; } - bool Daemon_Singleton::init(int argc, char* argv[]) - { + bool Daemon_Singleton::init(int argc, char* argv[]) { + return init(argc, argv, nullptr); + } + + bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr logstream) + { i2p::config::Init(); i2p::config::ParseCmdline(argc, argv); @@ -104,7 +108,10 @@ namespace i2p logs = "file"; i2p::log::Logger().SetLogLevel(loglevel); - if (logs == "file") { + if (logstream) { + LogPrint(eLogInfo, "Log: will send messages to std::ostream"); + i2p::log::Logger().SendTo (logstream); + } else if (logs == "file") { if (logfile == "") logfile = i2p::fs::DataDirPath("i2pd.log"); LogPrint(eLogInfo, "Log: will send messages to ", logfile); diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 00baf7b9..1745b980 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -3,6 +3,7 @@ #include #include +#include namespace i2p { @@ -12,8 +13,9 @@ namespace util class Daemon_Singleton { public: - virtual bool init(int argc, char* argv[]); - virtual bool start(); + virtual bool init(int argc, char* argv[], std::shared_ptr logstream); + virtual bool init(int argc, char* argv[]); + virtual bool start(); virtual bool stop(); virtual void run () {}; diff --git a/libi2pd/Log.cpp b/libi2pd/Log.cpp index b664a5d9..79b4a511 100644 --- a/libi2pd/Log.cpp +++ b/libi2pd/Log.cpp @@ -8,6 +8,9 @@ #include "Log.h" +//for std::transform +#include + namespace i2p { namespace log { static Log logger; @@ -107,7 +110,18 @@ namespace log { } } - void Log::SetLogLevel (const std::string& level) { + std::string str_tolower(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + // static_cast(std::tolower) // wrong + // [](int c){ return std::tolower(c); } // wrong + // [](char c){ return std::tolower(c); } // wrong + [](unsigned char c){ return std::tolower(c); } // correct + ); + return s; + } + + void Log::SetLogLevel (const std::string& level_) { + std::string level=str_tolower(level_); if (level == "none") { m_MinLevel = eLogNone; } else if (level == "error") { m_MinLevel = eLogError; } else if (level == "warn") { m_MinLevel = eLogWarning; } diff --git a/qt/i2pd_qt/DaemonQT.cpp b/qt/i2pd_qt/DaemonQT.cpp index dd7c892d..f5e6d62b 100644 --- a/qt/i2pd_qt/DaemonQT.cpp +++ b/qt/i2pd_qt/DaemonQT.cpp @@ -1,6 +1,11 @@ +#include + #include "DaemonQT.h" #include "Daemon.h" #include "mainwindow.h" + +#include "Log.h" + #include #include #include @@ -90,12 +95,12 @@ namespace qt delete mutex; } - bool DaemonQTImpl::init(int argc, char* argv[]) + bool DaemonQTImpl::init(int argc, char* argv[], std::shared_ptr logstream) { mutex=new QMutex(QMutex::Recursive); setRunningCallback(0); m_IsRunning=false; - return Daemon.init(argc,argv); + return Daemon.init(argc,argv,logstream); } void DaemonQTImpl::start() @@ -146,33 +151,35 @@ namespace qt int result; { + std::shared_ptr logstreamptr=std::make_shared(); + //TODO move daemon init deinit to a bg thread DaemonQTImpl daemon; - qDebug("Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(argc, argv); + (*logstreamptr) << "Initialising the daemon..." << std::endl; + bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr); if(!daemonInitSuccess) { QMessageBox::critical(0, "Error", "Daemon init failed"); return 1; } - qDebug("Initialised, creating the main window..."); - MainWindow w; - qDebug("Before main window.show()..."); + LogPrint(eLogDebug, "Initialised, creating the main window..."); + MainWindow w(logstreamptr); + LogPrint(eLogDebug, "Before main window.show()..."); w.show (); { i2p::qt::Controller daemonQtController(daemon); w.setI2PController(&daemonQtController); - qDebug("Starting the daemon..."); + LogPrint(eLogDebug, "Starting the daemon..."); emit daemonQtController.startDaemon(); //daemon.start (); - qDebug("Starting GUI event loop..."); + LogPrint(eLogDebug, "Starting GUI event loop..."); result = app.exec(); //daemon.stop (); } } //QMessageBox::information(&w, "Debug", "demon stopped"); - qDebug("Exiting the application"); + LogPrint(eLogDebug, "Exiting the application"); return result; } } diff --git a/qt/i2pd_qt/DaemonQT.h b/qt/i2pd_qt/DaemonQT.h index d0add0e3..780d2f73 100644 --- a/qt/i2pd_qt/DaemonQT.h +++ b/qt/i2pd_qt/DaemonQT.h @@ -25,7 +25,7 @@ namespace qt * @param argv * @return success */ - bool init(int argc, char* argv[]); + bool init(int argc, char* argv[], std::shared_ptr logstream); void start(); void stop(); void restart(); diff --git a/qt/i2pd_qt/SignatureTypeComboboxFactory.h b/qt/i2pd_qt/SignatureTypeComboboxFactory.h index 41245dac..f7cac658 100644 --- a/qt/i2pd_qt/SignatureTypeComboboxFactory.h +++ b/qt/i2pd_qt/SignatureTypeComboboxFactory.h @@ -18,7 +18,7 @@ class SignatureTypeComboBoxFactory } public: - static const uint16_t getSigType(const QVariant& var) { + static uint16_t getSigType(const QVariant& var) { return (uint16_t)var.toInt(); } diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 86cf579e..6c0464ab 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -93,7 +93,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ textbrowsertweaked1.cpp \ pagewithbackbutton.cpp \ widgetlock.cpp \ - widgetlockregistry.cpp + widgetlockregistry.cpp \ + logviewermanager.cpp #qt creator does not handle this well #SOURCES += $$files(../../libi2pd/*.cpp) @@ -179,7 +180,8 @@ HEADERS += DaemonQT.h mainwindow.h \ widgetlock.h \ widgetlockregistry.h \ i2pd.rc \ - i2pd.rc + i2pd.rc \ + logviewermanager.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client diff --git a/qt/i2pd_qt/logviewermanager.cpp b/qt/i2pd_qt/logviewermanager.cpp new file mode 100644 index 00000000..30fc904a --- /dev/null +++ b/qt/i2pd_qt/logviewermanager.cpp @@ -0,0 +1,45 @@ +#include "logviewermanager.h" + +LogViewerManager::LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent) : + QObject(parent), + logStream(logStream_), + logTextEdit(logTextEdit_), + controllerForBgThread(nullptr) +{ + assert(logTextEdit!=nullptr); + controllerForBgThread=new i2pd::qt::logviewer::Controller(*this); +} + +namespace i2pd { +namespace qt { +namespace logviewer { + +QString Worker::pollAndShootATimerForInfiniteRetries() { + std::shared_ptr logStream=logViewerManager.getLogStream(); + assert(logStream!=nullptr); + std::streamsize MAX_SZ=64*1024; + char*buf=(char*)malloc(MAX_SZ*sizeof(char)); + if(buf==nullptr)return ""; + std::streamsize read=logStream->readsome(buf, MAX_SZ); + if(read<0)read=0; + QString ret=QString::fromUtf8(buf, read); + free(buf); + return ret; +} + +Controller::Controller(LogViewerManager ¶meter1):logViewerManager(parameter1) { + Worker *worker = new Worker(parameter1); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::operate1, worker, &Worker::doWork1); + connect(worker, &Worker::resultReady, + ¶meter1, &LogViewerManager::appendPlainText_atGuiThread); + workerThread.start(); + timerId=startTimer(100/*millis*/); +} + +} +} +} diff --git a/qt/i2pd_qt/logviewermanager.h b/qt/i2pd_qt/logviewermanager.h new file mode 100644 index 00000000..e9ede79f --- /dev/null +++ b/qt/i2pd_qt/logviewermanager.h @@ -0,0 +1,130 @@ +#ifndef LOGVIEWERMANAGER_H +#define LOGVIEWERMANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "FS.h" +#include "Log.h" + +class LogViewerManager; + +namespace i2pd { +namespace qt { +namespace logviewer { + +class Worker : public QObject +{ + Q_OBJECT +private: + LogViewerManager &logViewerManager; +public: + Worker(LogViewerManager ¶meter1):logViewerManager(parameter1){} +private: + QString pollAndShootATimerForInfiniteRetries(); + +public slots: + void doWork1() { + /* ... here is the expensive or blocking operation ... */ + QString read=pollAndShootATimerForInfiniteRetries(); + emit resultReady(read); + } + +signals: + void resultReady(QString read); +}; + +class Controller : public QObject +{ + Q_OBJECT + QThread workerThread; + LogViewerManager& logViewerManager; + int timerId; +public: + Controller(LogViewerManager ¶meter1); + ~Controller() { + if(timerId!=0)killTimer(timerId); + workerThread.quit(); + workerThread.wait(); + } +signals: + void operate1(); +protected: + void timerEvent(QTimerEvent */*event*/) { + emit operate1(); + } +}; + +} +} +} + +class LogViewerManager : public QObject +{ + Q_OBJECT +private: + std::shared_ptr logStream; + QPlainTextEdit* logTextEdit; + i2pd::qt::logviewer::Controller* controllerForBgThread; +public: + //also starts a bg thread (QTimer) polling logStream->readsome(buf, n) + explicit LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent); + //also deallocs the bg thread (QTimer) + virtual ~LogViewerManager(){} + const i2pd::qt::logviewer::Controller& getControllerForBgThread() { + assert(controllerForBgThread!=nullptr); + return *controllerForBgThread; + } + const QPlainTextEdit* getLogTextEdit(){ return logTextEdit; } + const std::shared_ptr getLogStream(){ return logStream; } +signals: + +public slots: + //void appendFromNonGuiThread(std::string read) { + //} +public slots: + void appendPlainText_atGuiThread(QString plainText) { + if(plainText.length()==0)return; + assert(logTextEdit!=nullptr); + int scrollPosVert =logTextEdit->verticalScrollBar()->value(); + int scrollPosHoriz=logTextEdit->horizontalScrollBar()->value(); + int scrollPosVertMax =logTextEdit->verticalScrollBar()->maximum(); + const int MAX_LINES=10*1024; + logTextEdit->setMaximumBlockCount(MAX_LINES); + //logTextEdit->appendPlainText(plainText); + //navigate the window to the end + //QTextCursor cursor = logTextEdit->textCursor(); + //cursor.movePosition(QTextCursor::MoveOperation::End); + //logTextEdit->setTextCursor(cursor); + //QTextCursor prev_cursor = logTextEdit->textCursor(); + logTextEdit->moveCursor(QTextCursor::End); + logTextEdit->insertPlainText(plainText); + if(/*prev_cursor.atEnd()*/scrollPosVert==scrollPosVertMax){ + //logTextEdit->moveCursor(QTextCursor::End); + scrollPosVert =logTextEdit->verticalScrollBar()->maximum(); + scrollPosHoriz=logTextEdit->horizontalScrollBar()->minimum(); + } + //else + // logTextEdit->setTextCursor(prev_cursor); + logTextEdit->verticalScrollBar()->setValue(scrollPosVert); + logTextEdit->horizontalScrollBar()->setValue(scrollPosHoriz); + } + /* + void replaceText_atGuiThread() { + assert(logTextEdit!=nullptr); + logTextEdit->setText(QString::fromStdString(nav.getContent())); + } + */ +}; + +#endif // LOGVIEWERMANAGER_H diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index a095f78c..e4c9f2a7 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -27,15 +27,19 @@ #include "DaemonQT.h" #include "SignatureTypeComboboxFactory.h" +#include "logviewermanager.h" + std::string programOptionsWriterCurrentSection; -MainWindow::MainWindow(QWidget *parent) : +MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *parent) : QMainWindow(parent) + ,logStream(logStream_) #ifndef ANDROID ,quitting(false) #endif ,wasSelectingAtStatusMainPage(false) ,showHiddenInfoStatusMainPage(false) + ,logViewerManagerPtr(nullptr) ,ui(new Ui::MainWindow) ,statusButtonsUI(new Ui::StatusButtonsForm) ,routerCommandsUI(new Ui::routerCommandsWidget) @@ -132,6 +136,8 @@ MainWindow::MainWindow(QWidget *parent) : QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit())); QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit())); + QObject::connect(ui->logViewerPushButton, SIGNAL(released()), this, SLOT(showLogViewerPage())); + QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage())); @@ -299,6 +305,9 @@ MainWindow::MainWindow(QWidget *parent) : trayIcon->show(); #endif + logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this); + assert(logViewerManagerPtr!=nullptr); + onLoggingOptionsChange(); //QMetaObject::connectSlotsByName(this); } @@ -333,10 +342,11 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){ } wasSelectingAtStatusMainPage=false; } -void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} -void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} -void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} -void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} +void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} +void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} +void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} +void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} +void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(5);setStatusButtonsVisible(false);} void MainWindow::setStatusButtonsVisible(bool visible) { ui->statusButtonsPane->setVisible(visible); @@ -631,6 +641,8 @@ void MainWindow::loadAllConfigs(){ } ReadTunnelsConfig(); + + onLoggingOptionsChange(); } /** returns false iff not valid items present and save was aborted */ bool MainWindow::saveAllConfigs(){ @@ -668,6 +680,8 @@ bool MainWindow::saveAllConfigs(){ SaveTunnelsConfig(); + onLoggingOptionsChange(); + return true; } diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index c5f0c902..51384f51 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -62,6 +62,8 @@ #include "widgetlockregistry.h" #include "widgetlock.h" +class LogViewerManager; + template bool isType(boost::any& a) { return @@ -215,7 +217,8 @@ public: }; class LogDestinationComboBoxItem : public ComboBoxItem { public: - LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : + ComboBoxItem(option_, comboBox_) {} virtual ~LogDestinationComboBoxItem(){} virtual void loadFromConfigOption(){ MainWindowItem::loadFromConfigOption(); @@ -228,6 +231,8 @@ public: MainWindowItem::saveToStringStream(out); } virtual bool isValid() { return true; } + + Q_OBJECT }; class LogLevelComboBoxItem : public ComboBoxItem { public: @@ -370,9 +375,10 @@ class Controller; class MainWindow : public QMainWindow { Q_OBJECT - +private: + std::shared_ptr logStream; public: - explicit MainWindow(QWidget *parent=0); + explicit MainWindow(std::shared_ptr logStream_, QWidget *parent=nullptr); ~MainWindow(); void setI2PController(i2p::qt::Controller* controller_); @@ -419,6 +425,7 @@ public slots: void showStatus_i2p_tunnels_Page(); void showStatus_sam_sessions_Page(); + void showLogViewerPage(); void showSettingsPage(); void showTunnelsPage(); void showRestartPage(); @@ -430,6 +437,8 @@ private: bool wasSelectingAtStatusMainPage; bool showHiddenInfoStatusMainPage; + LogViewerManager *logViewerManagerPtr; + void showStatusPage(StatusPage newStatusPage); #ifndef ANDROID void createActions(); @@ -522,13 +531,6 @@ private: void appendTunnelForms(std::string tunnelNameToFocus); void deleteTunnelForms(); - - /* - - TODO signaturetype - - */ - template std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const { @@ -790,6 +792,8 @@ private: }; TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener; + + void onLoggingOptionsChange() {} }; #endif // MAINWINDOW_H diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index 9b463f44..dcdf88bd 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -58,7 +58,7 @@ QLayout::SetMaximumSize - + QLayout::SetMinimumSize @@ -96,6 +96,13 @@ + + + + Log + + + @@ -596,7 +603,7 @@ - TextLabel + wrongInputMessageLabel true @@ -627,7 +634,7 @@ - 2 + 1 @@ -671,6 +678,69 @@ + + + + 0 + 0 + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Log + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + 10000 + + + false + + + true + + + + + + @@ -728,8 +798,8 @@ 0 0 - 689 - 496 + 81 + 28 From 5d86c1c9a65819aaa89ba32f5f77990362885a2f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 May 2018 14:27:26 -0400 Subject: [PATCH 058/115] ntcp2 crypto added --- libi2pd/ChaCha20.cpp | 147 +++++++++++++++++++++ libi2pd/ChaCha20.h | 26 ++++ libi2pd/Poly1305.cpp | 303 +++++++++++++++++++++++++++++++++++++++++++ libi2pd/Poly1305.h | 28 ++++ libi2pd/Siphash.h | 152 ++++++++++++++++++++++ 5 files changed, 656 insertions(+) create mode 100644 libi2pd/ChaCha20.cpp create mode 100644 libi2pd/ChaCha20.h create mode 100644 libi2pd/Poly1305.cpp create mode 100644 libi2pd/Poly1305.h create mode 100644 libi2pd/Siphash.h diff --git a/libi2pd/ChaCha20.cpp b/libi2pd/ChaCha20.cpp new file mode 100644 index 00000000..e43f1514 --- /dev/null +++ b/libi2pd/ChaCha20.cpp @@ -0,0 +1,147 @@ +#include "ChaCha20.h" + +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +namespace i2p +{ +namespace crypto +{ +namespace chacha +{ +constexpr int rounds = 20; +constexpr std::size_t blocksize = 64; + +void u32t8le(uint32_t v, uint8_t * p) +{ + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +uint32_t u8t32le(const uint8_t * p) +{ + uint32_t value = p[3]; + + value = (value << 8) | p[2]; + value = (value << 8) | p[1]; + value = (value << 8) | p[0]; + + return value; +} + +uint32_t rotl32(uint32_t x, int n) +{ + return x << n | (x >> (-n & 31)); +} + +void quarterround(uint32_t *x, int a, int b, int c, int d) +{ + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); +} + + struct State_t + { + State_t() {}; + State_t(State_t &&) = delete; + + State_t & operator += (const State_t & other) + { + for(int i = 0; i < 16; i++) + data[i] += other.data[i]; + return *this; + } + + void Copy(const State_t & other) + { + memcpy(data, other.data, sizeof(uint32_t) * 16); + } + uint32_t data[16]; + }; + + struct Block_t + { + Block_t() {}; + Block_t(Block_t &&) = delete; + + uint8_t data[blocksize]; + + void operator << (const State_t & st) + { + int i; + for (i = 0; i < 16; i++) + u32t8le(st.data[i], data + (i << 2)); + } + }; + +void block(const State_t &input, Block_t & block, int rounds) +{ + int i; + State_t x; + x.Copy(input); + + for (i = rounds; i > 0; i -= 2) + { + quarterround(x.data, 0, 4, 8, 12); + quarterround(x.data, 1, 5, 9, 13); + quarterround(x.data, 2, 6, 10, 14); + quarterround(x.data, 3, 7, 11, 15); + quarterround(x.data, 0, 5, 10, 15); + quarterround(x.data, 1, 6, 11, 12); + quarterround(x.data, 2, 7, 8, 13); + quarterround(x.data, 3, 4, 9, 14); + } + x += input; + block << x; + +} +} // namespace chacha + + + + + +void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter) +{ + chacha::State_t state; + chacha::Block_t block; + size_t i, j; + + state.data[0] = 0x61707865; + state.data[1] = 0x3320646e; + state.data[2] = 0x79622d32; + state.data[3] = 0x6b206574; + + for (i = 0; i < 8; i++) + state.data[4 + i] = chacha::u8t32le(key + i * 4); + + + state.data[12] = counter; + + for (i = 0; i < 3; i++) + state.data[13 + i] = chacha::u8t32le(nonce + i * 4); + + + for (i = 0; i < sz; i += chacha::blocksize) + { + chacha::block(state, block, chacha::rounds); + state.data[12]++; + for (j = i; j < i + chacha::blocksize; j++) + { + if (j >= sz) break; + buf[j] ^= block.data[j - i]; + } + } + +} + +} +} \ No newline at end of file diff --git a/libi2pd/ChaCha20.h b/libi2pd/ChaCha20.h new file mode 100644 index 00000000..c88325d5 --- /dev/null +++ b/libi2pd/ChaCha20.h @@ -0,0 +1,26 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef LIBI2PD_CHACHA20_H +#define LIBI2PD_CHACHA20_H +#include +#include + +namespace i2p +{ +namespace crypto +{ + const std::size_t CHACHA20_KEY_BYTES = 32; + const std::size_t CHACHA20_NOUNCE_BYTES = 12; + + /** encrypt buf in place with chacha20 */ + void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1); + +} +} + +#endif diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp new file mode 100644 index 00000000..355555c6 --- /dev/null +++ b/libi2pd/Poly1305.cpp @@ -0,0 +1,303 @@ +#include "Poly1305.h" +#include "CPU.h" +#include +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +namespace i2p +{ +namespace crypto +{ +#if 0 +#ifdef __AVX2__ + struct Poly1305_AVX2 + { + Poly1305_AVX2(const uint32_t *& k) + { + __asm__ + ( + "VMOVNTDQA %[key0], %%ymm0 \n" + "VMOVNTDQA 32%[key0], %%ymm1 \n" + : + : + [key0]"m"(k) + ); + }; + + ~Poly1305_AVX2() + { + // clear out registers + __asm__ + ( + "VZEROALL\n" + ); + } + + void Update(const uint8_t * buf, size_t sz) + { + + } + + void Finish(uint32_t *& out) + { + + } + + + + size_t leftover; + + }; +#endif +#endif + namespace poly1305 + { + + struct LongBlock + { + unsigned long data[17]; + operator unsigned long * () + { + return data; + } + }; + + struct Block + { + unsigned char data[17]; + + operator uint8_t * () + { + return data; + } + + Block & operator += (const Block & other) + { + unsigned short u; + unsigned int i; + for(u = 0, i = 0; i < 17; i++) + { + u += (unsigned short) data[i] + (unsigned short) other.data[i]; + data[i] = (unsigned char) u & 0xff; + u >>= 8; + } + return *this; + } + + Block & operator %=(const LongBlock & other) + { + unsigned long u; + unsigned int i; + u = 0; + for (i = 0; i < 16; i++) { + u += other.data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + u += other.data[16]; + data[16] = (unsigned char)u & 0x03; + u >>= 2; + u += (u << 2); + for (i = 0; i < 16; i++) { + u += data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + data[16] += (unsigned char)u; + return *this; + } + + Block & operator = (const Block & other) + { + memcpy(data, other.data, sizeof(data)); + return *this; + } + + Block & operator ~ () + { + static const Block minusp = { + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfc + }; + Block orig; + unsigned char neg; + unsigned int i; + orig = *this; + *this += minusp; + neg = -(data[16] >> 7); + for(i = 0; i < 17; i++) + data[i] ^= neg & (orig.data[i] ^ data[i]); + + return *this; + } + + void PutKey(const uint8_t * key) + { + data[0] = key[0] & 0xff; + data[1] = key[1] & 0xff; + data[2] = key[2] & 0xff; + data[3] = key[3] & 0x0f; + data[4] = key[4] & 0xfc; + data[5] = key[5] & 0xff; + data[6] = key[6] & 0xff; + data[7] = key[7] & 0x0f; + data[8] = key[8] & 0xfc; + data[9] = key[9] & 0xff; + data[10] = key[10] & 0xff; + data[11] = key[11] & 0x0f; + data[12] = key[12] & 0xfc; + data[13] = key[13] & 0xff; + data[14] = key[14] & 0xff; + data[15] = key[15] & 0x0f; + data[16] = 0; + } + + void Put(const uint8_t * d, uint8_t last=0) + { + memcpy(data, d, 17); + data[16] = last; + } + }; + + struct Buffer + { + uint8_t data[POLY1305_BLOCK_BYTES]; + + operator uint8_t * () + { + return data; + } + }; + } + + struct Poly1305 + { + + Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) + { + m_R.PutKey(key); + m_Pad.Put(key + 16); + } + + void Update(const uint8_t * buf, size_t sz) + { + // process leftover + if(m_Leftover) + { + size_t want = POLY1305_BLOCK_BYTES - m_Leftover; + if(want > sz) want = sz; + memcpy(m_Buffer + m_Leftover, buf, want); + sz -= want; + buf += want; + m_Leftover += want; + if(m_Leftover < POLY1305_BLOCK_BYTES) return; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + m_Leftover = 0; + } + // process blocks + if(sz >= POLY1305_BLOCK_BYTES) + { + size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1)); + Blocks(buf, want); + buf += want; + sz -= want; + } + // leftover + if(sz) + { + memcpy(m_Buffer+m_Leftover, buf, sz); + m_Leftover += sz; + } + } + + void Blocks(const uint8_t * buf, size_t sz) + { + const unsigned char hi = m_Final ^ 1; + while (sz >= POLY1305_BLOCK_BYTES) { + + unsigned long u; + + unsigned int i, j; + m_Msg.Put(buf, hi); + /* h += m */ + m_H += m_Msg; + + /* h *= r */ + for (i = 0; i < 17; i++) { + u = 0; + for (j = 0; j <= i ; j++) { + u += (unsigned short)m_H.data[j] * m_R.data[i - j]; + } + for (j = i + 1; j < 17; j++) { + unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j]; + v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ + u += v; + } + m_HR[i] = u; + } + /* (partial) h %= p */ + m_H %= m_HR; + buf += POLY1305_BLOCK_BYTES; + sz -= POLY1305_BLOCK_BYTES; + } + } + + void Finish(uint32_t *& out) + { + // process leftovers + if(m_Leftover) + { + size_t idx = m_Leftover; + m_Buffer[idx++] = 1; + for(; idx < POLY1305_BLOCK_BYTES; idx++) + m_Buffer[idx] = 0; + m_Final = 1; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + } + + // freeze H + ~m_H; + // add pad + m_H += m_Pad; + // copy digest + memcpy(out, m_H, 16); + } + + size_t m_Leftover; + poly1305::Buffer m_Buffer; + poly1305::Block m_H; + poly1305::Block m_R; + poly1305::Block m_Pad; + poly1305::Block m_Msg; + poly1305::LongBlock m_HR; + uint8_t m_Final; + + }; + + void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz) + { + #if 0 + #ifdef __AVX2__ + if(i2p::cpu::avx2) + { + Poly1305_AVX2 p(key); + p.Update(buf, sz); + p.Finish(out); + } + else + #endif + #endif + { + const uint8_t * k = (const uint8_t *) key; + Poly1305 p(k); + p.Update(buf, sz); + p.Finish(out); + } + } +} +} diff --git a/libi2pd/Poly1305.h b/libi2pd/Poly1305.h new file mode 100644 index 00000000..2c62c5aa --- /dev/null +++ b/libi2pd/Poly1305.h @@ -0,0 +1,28 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef LIBI2PD_POLY1305_H +#define LIBI2PD_POLY1305_H +#include +#include + +namespace i2p +{ +namespace crypto +{ + const std::size_t POLY1305_DIGEST_BYTES = 16; + const std::size_t POLY1305_DIGEST_DWORDS = 4; + const std::size_t POLY1305_KEY_BYTES = 32; + const std::size_t POLY1305_KEY_DWORDS = 8; + const std::size_t POLY1305_BLOCK_BYTES = 16; + + void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz); + +} +} + +#endif diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h new file mode 100644 index 00000000..3e74c6e9 --- /dev/null +++ b/libi2pd/Siphash.h @@ -0,0 +1,152 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef SIPHASH_H +#define SIPHASH_H + +#include + +namespace i2p +{ +namespace crypto +{ + namespace siphash + { + constexpr int crounds = 2; + constexpr int drounds = 4; + + uint64_t rotl(const uint64_t & x, int b) + { + uint64_t ret = x << b; + ret |= x >> (64 - b); + return ret; + } + + void u32to8le(const uint32_t & v, uint8_t * p) + { + p[0] = (uint8_t) v; + p[1] = (uint8_t) (v >> 8); + p[2] = (uint8_t) (v >> 16); + p[3] = (uint8_t) (v >> 24); + } + + void u64to8le(const uint64_t & v, uint8_t * p) + { + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + p[4] = (v >> 32) & 0xff; + p[5] = (v >> 40) & 0xff; + p[6] = (v >> 48) & 0xff; + p[7] = (v >> 56) & 0xff; + } + + uint64_t u8to64le(const uint8_t * p) + { + uint64_t i = 0; + int idx = 0; + while(idx < 8) + { + i |= ((uint64_t) p[idx]) << (idx * 8); + ++idx; + } + return i; + } + + void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) + { + _v0 += _v1; + _v1 = rotl(_v1, 13); + _v1 ^= _v0; + _v0 = rotl(_v0, 32); + _v2 += _v3; + _v3 = rotl(_v3, 16); + _v3 ^= _v2; + _v0 += _v3; + _v3 = rotl(_v3, 21); + _v3 ^= _v0; + _v2 += _v1; + _v1 = rotl(_v1, 17); + _v1 ^= _v2; + _v2 = rotl(_v2, 32); + } + } + + /** hashsz must be 8 or 16 */ + template + void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) + { + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f6dULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + const uint64_t k0 = siphash::u8to64le(key); + const uint64_t k1 = siphash::u8to64le(key + 8); + uint64_t msg; + int i; + const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t)); + auto left = bufsz & 7; + uint64_t b = ((uint64_t)bufsz) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if(hashsz == 16) v1 ^= 0xee; + + while(buf != end) + { + msg = siphash::u8to64le(buf); + v3 ^= msg; + for(i = 0; i < siphash::crounds; ++i) + siphash::round(v0, v1, v2, v3); + + v0 ^= msg; + buf += 8; + } + + while(left) + { + --left; + b |= ((uint64_t)(buf[left])) << (left * 8); + } + + v3 ^= b; + + for(i = 0; i < siphash::crounds; ++i) + siphash::round(v0, v1, v2, v3); + + v0 ^= b; + + + if(hashsz == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + for(i = 0; i < siphash::drounds; ++i) + siphash::round(v0, v1, v2, v3); + + b = v0 ^ v1 ^ v2 ^ v3; + + siphash::u64to8le(b, h); + + if(hashsz == 8) return; + + v1 ^= 0xdd; + + for (i = 0; i < siphash::drounds; ++i) + siphash::round(v0, v1, v2, v3); + + b = v0 ^ v1 ^ v2 ^ v3; + siphash::u64to8le(b, h + 8); + } +} +} + +#endif \ No newline at end of file From 516f140bef4cafa9fea860dd2e5f34021d30f237 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 May 2018 14:32:14 -0400 Subject: [PATCH 059/115] ntcp2 crypto added --- build/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index fc9ca417..8ea4bfcc 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -77,6 +77,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/api.cpp" "${LIBI2PD_SRC_DIR}/Event.cpp" "${LIBI2PD_SRC_DIR}/Gost.cpp" + "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" + "${LIBI2PD_SRC_DIR}/Poly1305.cpp" ) if (WITH_WEBSOCKETS) From 4cedaa9e807ec5bcd104c546994d24089a6b60b5 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 May 2018 09:49:59 -0400 Subject: [PATCH 060/115] fixed android build --- libi2pd/Poly1305.cpp | 65 +++----------------------------------------- 1 file changed, 4 insertions(+), 61 deletions(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index 355555c6..5378d3cb 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -1,6 +1,4 @@ #include "Poly1305.h" -#include "CPU.h" -#include /** This code is licensed under the MCGSI Public License Copyright 2018 Jeff Becker @@ -12,48 +10,6 @@ namespace i2p { namespace crypto { -#if 0 -#ifdef __AVX2__ - struct Poly1305_AVX2 - { - Poly1305_AVX2(const uint32_t *& k) - { - __asm__ - ( - "VMOVNTDQA %[key0], %%ymm0 \n" - "VMOVNTDQA 32%[key0], %%ymm1 \n" - : - : - [key0]"m"(k) - ); - }; - - ~Poly1305_AVX2() - { - // clear out registers - __asm__ - ( - "VZEROALL\n" - ); - } - - void Update(const uint8_t * buf, size_t sz) - { - - } - - void Finish(uint32_t *& out) - { - - } - - - - size_t leftover; - - }; -#endif -#endif namespace poly1305 { @@ -281,23 +237,10 @@ namespace crypto void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz) { - #if 0 - #ifdef __AVX2__ - if(i2p::cpu::avx2) - { - Poly1305_AVX2 p(key); - p.Update(buf, sz); - p.Finish(out); - } - else - #endif - #endif - { - const uint8_t * k = (const uint8_t *) key; - Poly1305 p(k); - p.Update(buf, sz); - p.Finish(out); - } + const uint8_t * k = (const uint8_t *) key; + Poly1305 p(k); + p.Update(buf, sz); + p.Finish(out); } } } From 56e76ec59fe7456e67182d4317099dfc26dec7ed Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 28 May 2018 19:41:23 +0300 Subject: [PATCH 061/115] fix using debug library compilation in release mode --- android/build.gradle | 4 ++-- android/jni/Application.mk | 3 ++- android_binary_only/jni/Application.mk | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 4fe17d88..d58e098f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -19,7 +19,7 @@ repositories { android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion "25.0.3" defaultConfig { applicationId "org.purplei2p.i2pd" targetSdkVersion 25 @@ -49,7 +49,7 @@ android { } buildTypes { release { - minifyEnabled false + minifyEnabled true signingConfig signingConfigs.orignal proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' } diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0fa116c2..b5b920fa 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -19,7 +19,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif -APP_OPTIM := debug +# 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/OpenSSL-for-Android-Prebuilt.git diff --git a/android_binary_only/jni/Application.mk b/android_binary_only/jni/Application.mk index 7cd5c813..b8cdc2ab 100755 --- a/android_binary_only/jni/Application.mk +++ b/android_binary_only/jni/Application.mk @@ -21,7 +21,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif -APP_OPTIM := debug +# 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/OpenSSL-for-Android-Prebuilt.git From 46283dc0eaeae24026456c92c3f7d2ef31640f1b Mon Sep 17 00:00:00 2001 From: Veggie Monster Date: Mon, 28 May 2018 17:00:47 -0400 Subject: [PATCH 062/115] fixes #1124 and calls the ready callbacks if the tunnel gets ready and no timeout is set --- libi2pd_client/I2PService.cpp | 23 +++++++++++------------ libi2pd_client/I2PService.h | 3 +++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 21e1fdfa..da8dd65a 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -14,6 +14,7 @@ namespace client m_LocalDestination (localDestination ? localDestination : i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), m_ReadyTimer(m_LocalDestination->GetService()), + m_ReadyTimerTriggered(false), m_ConnectTimeout(0), isUpdated (true) { @@ -47,29 +48,25 @@ namespace client void I2PService::SetConnectTimeout(uint32_t timeout) { - if(timeout && !m_ConnectTimeout) - { - TriggerReadyCheckTimer(); - } - else if (m_ConnectTimeout && !timeout) - { - m_ReadyTimer.cancel(); - } m_ConnectTimeout = timeout; } void I2PService::AddReadyCallback(ReadyCallback cb) { uint32_t now = i2p::util::GetSecondsSinceEpoch(); - uint32_t tm = now + m_ConnectTimeout; + uint32_t tm = (m_ConnectTimeout) ? now + m_ConnectTimeout : NEVER_TIMES_OUT; + LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now); m_ReadyCallbacks.push_back({cb, tm}); + if (!m_ReadyTimerTriggered) TriggerReadyCheckTimer(); } void I2PService::TriggerReadyCheckTimer() { m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1)); m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_1)); + m_ReadyTimerTriggered = true; + } void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec) @@ -87,7 +84,7 @@ namespace client auto itr = m_ReadyCallbacks.begin(); while(itr != m_ReadyCallbacks.end()) { - if(itr->second >= now) + if(itr->second != NEVER_TIMES_OUT && now >= itr->second) { itr->first(boost::asio::error::timed_out); itr = m_ReadyCallbacks.erase(itr); @@ -96,8 +93,10 @@ namespace client ++itr; } } - if(!ec) - TriggerReadyCheckTimer(); + if(!ec && m_ReadyCallbacks.size()) + TriggerReadyCheckTimer(); + else + m_ReadyTimerTriggered = false; } void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) { diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index ecfd5bc5..55921898 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -67,8 +67,11 @@ namespace client std::mutex m_HandlersMutex; std::vector > m_ReadyCallbacks; boost::asio::deadline_timer m_ReadyTimer; + bool m_ReadyTimerTriggered; uint32_t m_ConnectTimeout; + const size_t NEVER_TIMES_OUT = 0; + public: bool isUpdated; // transient, used during reload only }; From cd0f75106a4d8f51b02b85c1b230617467517892 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jun 2018 16:06:38 -0400 Subject: [PATCH 063/115] moved Ed25519 away from signature --- build/CMakeLists.txt | 3 +- libi2pd/Ed25519.cpp | 429 +++++++++++++++++++++++++++++++++++++++++ libi2pd/Ed25519.h | 117 ++++++++++++ libi2pd/Signature.cpp | 436 ------------------------------------------ libi2pd/Signature.h | 57 +----- 5 files changed, 549 insertions(+), 493 deletions(-) create mode 100644 libi2pd/Ed25519.cpp create mode 100644 libi2pd/Ed25519.h diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 8ea4bfcc..299ca438 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -78,7 +78,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/Event.cpp" "${LIBI2PD_SRC_DIR}/Gost.cpp" "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" - "${LIBI2PD_SRC_DIR}/Poly1305.cpp" + "${LIBI2PD_SRC_DIR}/Poly1305.cpp" + "${LIBI2PD_SRC_DIR}/Ed25519.cpp" ) if (WITH_WEBSOCKETS) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp new file mode 100644 index 00000000..956f52fc --- /dev/null +++ b/libi2pd/Ed25519.cpp @@ -0,0 +1,429 @@ +#include +#include "Log.h" +#include "Crypto.h" +#include "Ed25519.h" + +namespace i2p +{ +namespace crypto +{ + Ed25519::Ed25519 () + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * tmp = BN_new (); + + q = BN_new (); + // 2^255-19 + BN_set_bit (q, 255); // 2^255 + BN_sub_word (q, 19); + + l = BN_new (); + // 2^252 + 27742317777372353535851937790883648493 + BN_set_bit (l, 252); + two_252_2 = BN_dup (l); + BN_dec2bn (&tmp, "27742317777372353535851937790883648493"); + BN_add (l, l, tmp); + BN_sub_word (two_252_2, 2); // 2^252 - 2 + + // -121665*inv(121666) + d = BN_new (); + BN_set_word (tmp, 121666); + BN_mod_inverse (tmp, tmp, q, ctx); + BN_set_word (d, 121665); + BN_set_negative (d, 1); + BN_mul (d, d, tmp, ctx); + + // 2^((q-1)/4) + I = BN_new (); + BN_free (tmp); + tmp = BN_dup (q); + BN_sub_word (tmp, 1); + BN_div_word (tmp, 4); + BN_set_word (I, 2); + BN_mod_exp (I, I, tmp, q, ctx); + BN_free (tmp); + + // 4*inv(5) + BIGNUM * By = BN_new (); + BN_set_word (By, 5); + BN_mod_inverse (By, By, q, ctx); + BN_mul_word (By, 4); + BIGNUM * Bx = RecoverX (By, ctx); + BN_mod (Bx, Bx, q, ctx); // % q + BN_mod (By, By, q, ctx); // % q + + // precalculate Bi256 table + Bi256Carry = { Bx, By }; // B + for (int i = 0; i < 32; i++) + { + Bi256[i][0] = Bi256Carry; // first point + for (int j = 1; j < 128; j++) + Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B + Bi256Carry = Bi256[i][127]; + for (int j = 0; j < 128; j++) // add first point 128 more times + Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx); + } + + BN_CTX_free (ctx); + } + + Ed25519::Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)), + d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), + Bi256Carry (other.Bi256Carry) + { + for (int i = 0; i < 32; i++) + for (int j = 0; j < 128; j++) + Bi256[i][j] = other.Bi256[i][j]; + } + + Ed25519::~Ed25519 () + { + BN_free (q); + BN_free (l); + BN_free (d); + BN_free (I); + BN_free (two_252_2); + } + + + EDDSAPoint Ed25519::GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const + { + return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian + } + + EDDSAPoint Ed25519::DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const + { + return DecodePoint (buf, ctx); + } + + void Ed25519::EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const + { + EncodePoint (Normalize (publicKey, ctx), buf); + } + + bool Ed25519::Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * h = DecodeBN<64> (digest); + // signature 0..31 - R, 32..63 - S + // B*S = R + PK*h => R = B*S - PK*h + // we don't decode R, but encode (B*S - PK*h) + auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S; + BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0 + auto PKh = Mul (publicKey, h, ctx); // PK*h + uint8_t diff[32]; + EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded + bool passed = !memcmp (signature, diff, 32); // R + BN_free (h); + BN_CTX_free (ctx); + if (!passed) + LogPrint (eLogError, "25519 signature verification failed"); + return passed; + } + + void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, + uint8_t * signature) const + { + BN_CTX * bnCtx = BN_CTX_new (); + // calculate r + SHA512_CTX ctx; + SHA512_Init (&ctx); + SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key + SHA512_Update (&ctx, buf, len); // data + uint8_t digest[64]; + SHA512_Final (digest, &ctx); + BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors + // calculate R + uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf + EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors + // calculate S + SHA512_Init (&ctx); + SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + SHA512_Update (&ctx, buf, len); // data + SHA512_Final (digest, &ctx); + BIGNUM * h = DecodeBN<64> (digest); + // S = (r + h*a) % l + BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key + BN_mod_mul (h, h, a, l, bnCtx); // %l + BN_mod_add (h, h, r, l, bnCtx); // %l + memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); + EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S + BN_free (r); BN_free (h); BN_free (a); + BN_CTX_free (bnCtx); + } + + EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const + { + // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) + // y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2) + // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) + // t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2) + BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new (); + + BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 + BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 + + BN_CTX_start (ctx); + BIGNUM * t1 = p1.t, * t2 = p2.t; + if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } + if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } + BN_mul (t3, t1, t2, ctx); + BN_mul (t3, t3, d, ctx); // C = d*t1*t2 + + if (p1.z) + { + if (p2.z) + BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2 + else + BN_copy (z3, p1.z); // D = z1 + } + else + { + if (p2.z) + BN_copy (z3, p2.z); // D = z2 + else + BN_one (z3); // D = 1 + } + + BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); + BN_add (E, p1.x, p1.y); + BN_add (F, p2.x, p2.y); + BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2) + BN_sub (E, E, x3); + BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B + BN_sub (F, z3, t3); // F = D - C + BN_add (G, z3, t3); // G = D + C + BN_add (H, y3, x3); // H = B + A + + BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F + BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H + BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G + BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H + + BN_CTX_end (ctx); + + return EDDSAPoint {x3, y3, z3, t3}; + } + + void Ed25519::Double (EDDSAPoint& p, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx); + + BN_sqr (x2, p.x, ctx); // x2 = A = x^2 + BN_sqr (y2, p.y, ctx); // y2 = B = y^2 + if (p.t) + BN_sqr (t2, p.t, ctx); // t2 = t^2 + else + { + BN_mul (t2, p.x, p.y, ctx); // t = x*y + BN_sqr (t2, t2, ctx); // t2 = t^2 + } + BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 + if (p.z) + BN_sqr (z2, p.z, ctx); // z2 = D = z^2 + else + BN_one (z2); // z2 = 1 + + BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); + // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy + BN_mul (E, p.x, p.y, ctx); + BN_lshift1 (E, E); // E =2*x*y + BN_sub (F, z2, t2); // F = D - C + BN_add (G, z2, t2); // G = D + C + BN_add (H, y2, x2); // H = B + A + + BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F + BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H + if (!p.z) p.z = BN_new (); + BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G + if (!p.t) p.t = BN_new (); + BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H + + BN_CTX_end (ctx); + } + + EDDSAPoint Ed25519::Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const + { + BIGNUM * zero = BN_new (), * one = BN_new (); + BN_zero (zero); BN_one (one); + EDDSAPoint res {zero, one}; + if (!BN_is_zero (e)) + { + int bitCount = BN_num_bits (e); + for (int i = bitCount - 1; i >= 0; i--) + { + Double (res, ctx); + if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); + } + } + return res; + } + + EDDSAPoint Ed25519::MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian + { + BIGNUM * zero = BN_new (), * one = BN_new (); + BN_zero (zero); BN_one (one); + EDDSAPoint res {zero, one}; + bool carry = false; + for (int i = 0; i < 32; i++) + { + uint8_t x = e[i]; + if (carry) + { + if (x < 255) + { + x++; + carry = false; + } + else + x = 0; + } + if (x > 0) + { + if (x <= 128) + res = Sum (res, Bi256[i][x-1], ctx); + else + { + res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x] + carry = true; + } + } + } + if (carry) res = Sum (res, Bi256Carry, ctx); + return res; + } + + EDDSAPoint Ed25519::Normalize (const EDDSAPoint& p, BN_CTX * ctx) const + { + if (p.z) + { + BIGNUM * x = BN_new (), * y = BN_new (); + BN_mod_inverse (y, p.z, q, ctx); + BN_mod_mul (x, p.x, y, q, ctx); // x = x/z + BN_mod_mul (y, p.y, y, q, ctx); // y = y/z + return EDDSAPoint{x, y}; + } + else + return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)}; + } + + bool Ed25519::IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx); + BN_sqr (x2, p.x, ctx); // x^2 + BN_sqr (y2, p.y, ctx); // y^2 + // y^2 - x^2 - 1 - d*x^2*y^2 + BN_mul (tmp, d, x2, ctx); + BN_mul (tmp, tmp, y2, ctx); + BN_sub (tmp, y2, tmp); + BN_sub (tmp, tmp, x2); + BN_sub_word (tmp, 1); + BN_mod (tmp, tmp, q, ctx); // % q + bool ret = BN_is_zero (tmp); + BN_CTX_end (ctx); + return ret; + } + + BIGNUM * Ed25519::RecoverX (const BIGNUM * y, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx); + BN_sqr (y2, y, ctx); // y^2 + // xx = (y^2 -1)*inv(d*y^2 +1) + BN_mul (xx, d, y2, ctx); + BN_add_word (xx, 1); + BN_mod_inverse (xx, xx, q, ctx); + BN_sub_word (y2, 1); + BN_mul (xx, y2, xx, ctx); + // x = srqt(xx) = xx^(2^252-2) + BIGNUM * x = BN_new (); + BN_mod_exp (x, xx, two_252_2, q, ctx); + // check (x^2 -xx) % q + BN_sqr (y2, x, ctx); + BN_mod_sub (y2, y2, xx, q, ctx); + if (!BN_is_zero (y2)) + BN_mod_mul (x, x, I, q, ctx); + if (BN_is_odd (x)) + BN_sub (x, q, x); + BN_CTX_end (ctx); + return x; + } + + EDDSAPoint Ed25519::DecodePoint (const uint8_t * buf, BN_CTX * ctx) const + { + // buf is 32 bytes Little Endian, convert it to Big Endian + uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH]; + for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes + { + buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i]; + buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i]; + } + bool isHighestBitSet = buf1[0] & 0x80; + if (isHighestBitSet) + buf1[0] &= 0x7f; // clear highest bit + BIGNUM * y = BN_new (); + BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); + BIGNUM * x = RecoverX (y, ctx); + if (BN_is_bit_set (x, 0) != isHighestBitSet) + BN_sub (x, q, x); // x = q - x + BIGNUM * z = BN_new (), * t = BN_new (); + BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t + EDDSAPoint p {x, y, z, t}; + if (!IsOnCurve (p, ctx)) + LogPrint (eLogError, "Decoded point is not on 25519"); + return p; + } + + void Ed25519::EncodePoint (const EDDSAPoint& p, uint8_t * buf) const + { + EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH); + if (BN_is_bit_set (p.x, 0)) // highest bit + buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit + } + + template + BIGNUM * Ed25519::DecodeBN (const uint8_t * buf) const + { + // buf is Little Endian convert it to Big Endian + uint8_t buf1[len]; + for (size_t i = 0; i < len/2; i++) // invert bytes + { + buf1[i] = buf[len -1 - i]; + buf1[len -1 - i] = buf[i]; + } + BIGNUM * res = BN_new (); + BN_bin2bn (buf1, len, res); + return res; + } + + void Ed25519::EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const + { + bn2buf (bn, buf, len); + // To Little Endian + for (size_t i = 0; i < len/2; i++) // invert bytes + { + uint8_t tmp = buf[i]; + buf[i] = buf[len -1 - i]; + buf[len -1 - i] = tmp; + } + } + + static std::unique_ptr g_Ed25519; + std::unique_ptr& GetEd25519 () + { + if (!g_Ed25519) + { + auto c = new Ed25519(); + if (!g_Ed25519) // make sure it was not created already + g_Ed25519.reset (c); + else + delete c; + } + return g_Ed25519; + } +} +} + diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h new file mode 100644 index 00000000..9222edb4 --- /dev/null +++ b/libi2pd/Ed25519.h @@ -0,0 +1,117 @@ +#ifndef ED25519_H__ +#define ED25519_H__ + +#include +#include + +namespace i2p +{ +namespace crypto +{ + struct EDDSAPoint + { + BIGNUM * x {nullptr}; + BIGNUM * y {nullptr}; + BIGNUM * z {nullptr}; + BIGNUM * t {nullptr}; // projective coordinates + + EDDSAPoint () {} + EDDSAPoint (const EDDSAPoint& other) { *this = other; } + EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } + EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) + : x(x1) + , y(y1) + , z(z1) + , t(t1) + {} + ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } + + EDDSAPoint& operator=(EDDSAPoint&& other) + { + if (this != &other) + { + BN_free (x); x = other.x; other.x = nullptr; + BN_free (y); y = other.y; other.y = nullptr; + BN_free (z); z = other.z; other.z = nullptr; + BN_free (t); t = other.t; other.t = nullptr; + } + return *this; + } + + EDDSAPoint& operator=(const EDDSAPoint& other) + { + if (this != &other) + { + BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; + BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; + BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; + BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; + } + return *this; + } + + EDDSAPoint operator-() const + { + BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL; + if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; + if (y) y1 = BN_dup (y); + if (z) z1 = BN_dup (z); + if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; + return EDDSAPoint {x1, y1, z1, t1}; + } + }; + + const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; + const size_t EDDSA25519_SIGNATURE_LENGTH = 64; + const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; + class Ed25519 + { + public: + + Ed25519 (); + Ed25519 (const Ed25519& other); + ~Ed25519 (); + + EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; + EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; + void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; + + bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; + void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; + + private: + + EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; + void Double (EDDSAPoint& p, BN_CTX * ctx) const; + EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const; + EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const; // B*e, e is 32 bytes Little Endian + EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const; + + bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const; + BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const; + EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const; + void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const; + + template + BIGNUM * DecodeBN (const uint8_t * buf) const; + void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; + + private: + + BIGNUM * q, * l, * d, * I; + // transient values + BIGNUM * two_252_2; // 2^252-2 + EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes + // if j > 128 we use 256 - j and carry 1 to next byte + // Bi256[0][0] = B, base point + EDDSAPoint Bi256Carry; // Bi256[32][0] + }; + + std::unique_ptr& GetEd25519 (); + +} +} + + +#endif + diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index aded9bc8..f9b7aebd 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -6,442 +6,6 @@ namespace i2p { namespace crypto { - class Ed25519 - { - public: - - Ed25519 () - { - BN_CTX * ctx = BN_CTX_new (); - BIGNUM * tmp = BN_new (); - - q = BN_new (); - // 2^255-19 - BN_set_bit (q, 255); // 2^255 - BN_sub_word (q, 19); - - l = BN_new (); - // 2^252 + 27742317777372353535851937790883648493 - BN_set_bit (l, 252); - two_252_2 = BN_dup (l); - BN_dec2bn (&tmp, "27742317777372353535851937790883648493"); - BN_add (l, l, tmp); - BN_sub_word (two_252_2, 2); // 2^252 - 2 - - // -121665*inv(121666) - d = BN_new (); - BN_set_word (tmp, 121666); - BN_mod_inverse (tmp, tmp, q, ctx); - BN_set_word (d, 121665); - BN_set_negative (d, 1); - BN_mul (d, d, tmp, ctx); - - // 2^((q-1)/4) - I = BN_new (); - BN_free (tmp); - tmp = BN_dup (q); - BN_sub_word (tmp, 1); - BN_div_word (tmp, 4); - BN_set_word (I, 2); - BN_mod_exp (I, I, tmp, q, ctx); - BN_free (tmp); - - // 4*inv(5) - BIGNUM * By = BN_new (); - BN_set_word (By, 5); - BN_mod_inverse (By, By, q, ctx); - BN_mul_word (By, 4); - BIGNUM * Bx = RecoverX (By, ctx); - BN_mod (Bx, Bx, q, ctx); // % q - BN_mod (By, By, q, ctx); // % q - - // precalculate Bi256 table - Bi256Carry = { Bx, By }; // B - for (int i = 0; i < 32; i++) - { - Bi256[i][0] = Bi256Carry; // first point - for (int j = 1; j < 128; j++) - Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B - Bi256Carry = Bi256[i][127]; - for (int j = 0; j < 128; j++) // add first point 128 more times - Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx); - } - - BN_CTX_free (ctx); - } - - Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)), - d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), - Bi256Carry (other.Bi256Carry) - { - for (int i = 0; i < 32; i++) - for (int j = 0; j < 128; j++) - Bi256[i][j] = other.Bi256[i][j]; - } - - ~Ed25519 () - { - BN_free (q); - BN_free (l); - BN_free (d); - BN_free (I); - BN_free (two_252_2); - } - - - EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const - { - return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian - } - - EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const - { - return DecodePoint (buf, ctx); - } - - void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const - { - EncodePoint (Normalize (publicKey, ctx), buf); - } - - bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const - { - BN_CTX * ctx = BN_CTX_new (); - BIGNUM * h = DecodeBN<64> (digest); - // signature 0..31 - R, 32..63 - S - // B*S = R + PK*h => R = B*S - PK*h - // we don't decode R, but encode (B*S - PK*h) - auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S; - BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0 - auto PKh = Mul (publicKey, h, ctx); // PK*h - uint8_t diff[32]; - EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded - bool passed = !memcmp (signature, diff, 32); // R - BN_free (h); - BN_CTX_free (ctx); - if (!passed) - LogPrint (eLogError, "25519 signature verification failed"); - return passed; - } - - void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, - uint8_t * signature) const - { - BN_CTX * bnCtx = BN_CTX_new (); - // calculate r - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key - SHA512_Update (&ctx, buf, len); // data - uint8_t digest[64]; - SHA512_Final (digest, &ctx); - BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors - // calculate R - uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf - EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors - // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); - BIGNUM * h = DecodeBN<64> (digest); - // S = (r + h*a) % l - BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key - BN_mod_mul (h, h, a, l, bnCtx); // %l - BN_mod_add (h, h, r, l, bnCtx); // %l - memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); - EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S - BN_free (r); BN_free (h); BN_free (a); - BN_CTX_free (bnCtx); - } - - private: - - EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const - { - // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) - // y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2) - // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) - // t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2) - BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new (); - - BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 - BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 - - BN_CTX_start (ctx); - BIGNUM * t1 = p1.t, * t2 = p2.t; - if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } - if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } - BN_mul (t3, t1, t2, ctx); - BN_mul (t3, t3, d, ctx); // C = d*t1*t2 - - if (p1.z) - { - if (p2.z) - BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2 - else - BN_copy (z3, p1.z); // D = z1 - } - else - { - if (p2.z) - BN_copy (z3, p2.z); // D = z2 - else - BN_one (z3); // D = 1 - } - - BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); - BN_add (E, p1.x, p1.y); - BN_add (F, p2.x, p2.y); - BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2) - BN_sub (E, E, x3); - BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B - BN_sub (F, z3, t3); // F = D - C - BN_add (G, z3, t3); // G = D + C - BN_add (H, y3, x3); // H = B + A - - BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F - BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H - BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G - BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H - - BN_CTX_end (ctx); - - return EDDSAPoint {x3, y3, z3, t3}; - } - - void Double (EDDSAPoint& p, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx); - - BN_sqr (x2, p.x, ctx); // x2 = A = x^2 - BN_sqr (y2, p.y, ctx); // y2 = B = y^2 - if (p.t) - BN_sqr (t2, p.t, ctx); // t2 = t^2 - else - { - BN_mul (t2, p.x, p.y, ctx); // t = x*y - BN_sqr (t2, t2, ctx); // t2 = t^2 - } - BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 - if (p.z) - BN_sqr (z2, p.z, ctx); // z2 = D = z^2 - else - BN_one (z2); // z2 = 1 - - BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); - // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy - BN_mul (E, p.x, p.y, ctx); - BN_lshift1 (E, E); // E =2*x*y - BN_sub (F, z2, t2); // F = D - C - BN_add (G, z2, t2); // G = D + C - BN_add (H, y2, x2); // H = B + A - - BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F - BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H - if (!p.z) p.z = BN_new (); - BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G - if (!p.t) p.t = BN_new (); - BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H - - BN_CTX_end (ctx); - } - - EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const - { - BIGNUM * zero = BN_new (), * one = BN_new (); - BN_zero (zero); BN_one (one); - EDDSAPoint res {zero, one}; - if (!BN_is_zero (e)) - { - int bitCount = BN_num_bits (e); - for (int i = bitCount - 1; i >= 0; i--) - { - Double (res, ctx); - if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); - } - } - return res; - } - - EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian - { - BIGNUM * zero = BN_new (), * one = BN_new (); - BN_zero (zero); BN_one (one); - EDDSAPoint res {zero, one}; - bool carry = false; - for (int i = 0; i < 32; i++) - { - uint8_t x = e[i]; - if (carry) - { - if (x < 255) - { - x++; - carry = false; - } - else - x = 0; - } - if (x > 0) - { - if (x <= 128) - res = Sum (res, Bi256[i][x-1], ctx); - else - { - res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x] - carry = true; - } - } - } - if (carry) res = Sum (res, Bi256Carry, ctx); - return res; - } - - EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const - { - if (p.z) - { - BIGNUM * x = BN_new (), * y = BN_new (); - BN_mod_inverse (y, p.z, q, ctx); - BN_mod_mul (x, p.x, y, q, ctx); // x = x/z - BN_mod_mul (y, p.y, y, q, ctx); // y = y/z - return EDDSAPoint{x, y}; - } - else - return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)}; - } - - bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx); - BN_sqr (x2, p.x, ctx); // x^2 - BN_sqr (y2, p.y, ctx); // y^2 - // y^2 - x^2 - 1 - d*x^2*y^2 - BN_mul (tmp, d, x2, ctx); - BN_mul (tmp, tmp, y2, ctx); - BN_sub (tmp, y2, tmp); - BN_sub (tmp, tmp, x2); - BN_sub_word (tmp, 1); - BN_mod (tmp, tmp, q, ctx); // % q - bool ret = BN_is_zero (tmp); - BN_CTX_end (ctx); - return ret; - } - - BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx); - BN_sqr (y2, y, ctx); // y^2 - // xx = (y^2 -1)*inv(d*y^2 +1) - BN_mul (xx, d, y2, ctx); - BN_add_word (xx, 1); - BN_mod_inverse (xx, xx, q, ctx); - BN_sub_word (y2, 1); - BN_mul (xx, y2, xx, ctx); - // x = srqt(xx) = xx^(2^252-2) - BIGNUM * x = BN_new (); - BN_mod_exp (x, xx, two_252_2, q, ctx); - // check (x^2 -xx) % q - BN_sqr (y2, x, ctx); - BN_mod_sub (y2, y2, xx, q, ctx); - if (!BN_is_zero (y2)) - BN_mod_mul (x, x, I, q, ctx); - if (BN_is_odd (x)) - BN_sub (x, q, x); - BN_CTX_end (ctx); - return x; - } - - EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const - { - // buf is 32 bytes Little Endian, convert it to Big Endian - uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH]; - for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes - { - buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i]; - buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i]; - } - bool isHighestBitSet = buf1[0] & 0x80; - if (isHighestBitSet) - buf1[0] &= 0x7f; // clear highest bit - BIGNUM * y = BN_new (); - BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); - BIGNUM * x = RecoverX (y, ctx); - if (BN_is_bit_set (x, 0) != isHighestBitSet) - BN_sub (x, q, x); // x = q - x - BIGNUM * z = BN_new (), * t = BN_new (); - BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t - EDDSAPoint p {x, y, z, t}; - if (!IsOnCurve (p, ctx)) - LogPrint (eLogError, "Decoded point is not on 25519"); - return p; - } - - void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const - { - EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH); - if (BN_is_bit_set (p.x, 0)) // highest bit - buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit - } - - template - BIGNUM * DecodeBN (const uint8_t * buf) const - { - // buf is Little Endian convert it to Big Endian - uint8_t buf1[len]; - for (size_t i = 0; i < len/2; i++) // invert bytes - { - buf1[i] = buf[len -1 - i]; - buf1[len -1 - i] = buf[i]; - } - BIGNUM * res = BN_new (); - BN_bin2bn (buf1, len, res); - return res; - } - - void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const - { - bn2buf (bn, buf, len); - // To Little Endian - for (size_t i = 0; i < len/2; i++) // invert bytes - { - uint8_t tmp = buf[i]; - buf[i] = buf[len -1 - i]; - buf[len -1 - i] = tmp; - } - } - - private: - - BIGNUM * q, * l, * d, * I; - // transient values - BIGNUM * two_252_2; // 2^252-2 - EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes - // if j > 128 we use 256 - j and carry 1 to next byte - // Bi256[0][0] = B, base point - EDDSAPoint Bi256Carry; // Bi256[32][0] - }; - - static std::unique_ptr g_Ed25519; - std::unique_ptr& GetEd25519 () - { - if (!g_Ed25519) - { - auto c = new Ed25519(); - if (!g_Ed25519) // make sure it was not created already - g_Ed25519.reset (c); - else - delete c; - } - return g_Ed25519; - } - - EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey) { memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 1e7db9f7..8b30a8e8 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -9,6 +9,7 @@ #include #include #include "Crypto.h" +#include "Ed25519.h" #include "Gost.h" namespace i2p @@ -361,62 +362,6 @@ namespace crypto typedef RSASigner RSASHA5124096Signer; // EdDSA - struct EDDSAPoint - { - BIGNUM * x {nullptr}; - BIGNUM * y {nullptr}; - BIGNUM * z {nullptr}; - BIGNUM * t {nullptr}; // projective coordinates - - EDDSAPoint () {} - EDDSAPoint (const EDDSAPoint& other) { *this = other; } - EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } - EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) - : x(x1) - , y(y1) - , z(z1) - , t(t1) - {} - ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } - - EDDSAPoint& operator=(EDDSAPoint&& other) - { - if (this != &other) - { - BN_free (x); x = other.x; other.x = nullptr; - BN_free (y); y = other.y; other.y = nullptr; - BN_free (z); z = other.z; other.z = nullptr; - BN_free (t); t = other.t; other.t = nullptr; - } - return *this; - } - - EDDSAPoint& operator=(const EDDSAPoint& other) - { - if (this != &other) - { - BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; - BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; - BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; - BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; - } - return *this; - } - - EDDSAPoint operator-() const - { - BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL; - if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; - if (y) y1 = BN_dup (y); - if (z) z1 = BN_dup (z); - if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; - return EDDSAPoint {x1, y1, z1, t1}; - } - }; - - const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; - const size_t EDDSA25519_SIGNATURE_LENGTH = 64; - const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; class EDDSA25519Verifier: public Verifier { public: From 86c19849820713366b82cc4995cb58f95095ca15 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 12:53:13 -0400 Subject: [PATCH 064/115] NTCP2 added --- build/CMakeLists.txt | 3 ++- libi2pd/Ed25519.cpp | 8 ++++++++ libi2pd/Ed25519.h | 2 ++ libi2pd/NTCP2.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 32 +++++++++++++++++++++++++++++++ libi2pd/Signature.cpp | 6 +----- 6 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 libi2pd/NTCP2.cpp create mode 100644 libi2pd/NTCP2.h diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 299ca438..632edc03 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -79,7 +79,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/Gost.cpp" "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" "${LIBI2PD_SRC_DIR}/Poly1305.cpp" - "${LIBI2PD_SRC_DIR}/Ed25519.cpp" + "${LIBI2PD_SRC_DIR}/Ed25519.cpp" + "${LIBI2PD_SRC_DIR}/NTCP2.cpp" ) if (WITH_WEBSOCKETS) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 956f52fc..e921bada 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,6 +411,14 @@ namespace crypto } } + void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) + { + SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey); + expandedKey[0] &= 0xF8; // drop last 3 bits + expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits + expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit + } + static std::unique_ptr g_Ed25519; std::unique_ptr& GetEd25519 () { diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index 9222edb4..c3b162a7 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -79,6 +79,8 @@ namespace crypto bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; + static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes + private: EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp new file mode 100644 index 00000000..907e1fd8 --- /dev/null +++ b/libi2pd/NTCP2.cpp @@ -0,0 +1,44 @@ +#include +#include "Crypto.h" +#include "Ed25519.h" +#include "ChaCha20.h" +#include "Poly1305.h" +#include "NTCP2.h" + +namespace i2p +{ +namespace transport +{ + NTCP2Session::NTCP2Session (std::shared_ptr in_RemoteRouter): + TransportSession (in_RemoteRouter, 30) + { + } + + NTCP2Session::~NTCP2Session () + { + } + + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) + { + uint8_t key[32]; + RAND_bytes (key, 32); + i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); + BN_CTX * ctx = BN_CTX_new (); + auto publicKey = i2p::crypto::GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); + i2p::crypto::GetEd25519 ()->EncodePublicKey (publicKey, pub, ctx); + BN_CTX_free (ctx); + } + + void NTCP2Session::SendSessionRequest (const uint8_t * iv) + { + i2p::crypto::AESAlignedBuffer<32> x; + CreateEphemeralKey (x); + // encrypt X + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); + encryption.SetIV (iv); + encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + } +} +} + diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h new file mode 100644 index 00000000..6dfea8ae --- /dev/null +++ b/libi2pd/NTCP2.h @@ -0,0 +1,32 @@ +#ifndef NTCP2_H__ +#define NTCP2_H__ + +#include +#include +#include "RouterInfo.h" +#include "TransportSession.h" + +namespace i2p +{ +namespace transport +{ + class NTCP2Session: public TransportSession, public std::enable_shared_from_this + { + public: + + NTCP2Session (std::shared_ptr in_RemoteRouter = nullptr); // TODO + ~NTCP2Session (); + + private: + + void CreateEphemeralKey (uint8_t * pub); + void SendSessionRequest (const uint8_t * iv); + + private: + + uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key + }; +} +} + +#endif diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index f9b7aebd..baa265bc 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -30,11 +30,7 @@ namespace crypto EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) { // expand key - SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey); - m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits - m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits - m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit - + Ed25519::ExpandPrivateKey (signingPrivateKey, m_ExpandedPrivateKey); // generate and encode public key BN_CTX * ctx = BN_CTX_new (); auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); From 8c9eaccc11e573fa821d3b02efcb4b9f925d214b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 15:37:08 -0400 Subject: [PATCH 065/115] KeyDerivationFunction for NTCP2 --- libi2pd/Ed25519.cpp | 8 ++++++++ libi2pd/Ed25519.h | 1 + libi2pd/NTCP2.cpp | 31 +++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 1 + 4 files changed, 41 insertions(+) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index e921bada..8258d33c 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,6 +411,14 @@ namespace crypto } } + void Ed25519::Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + auto P = DecodePublicKey (p, ctx); + BIGNUM * e1 = DecodeBN<32> (e); + EncodePublicKey (Mul (P, e1, ctx), buf, ctx); + BN_free (e1); + } + void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) { SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey); diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index c3b162a7..cbf14bfd 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -75,6 +75,7 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; + void Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 907e1fd8..e6072207 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Crypto.h" #include "Ed25519.h" #include "ChaCha20.h" @@ -18,6 +20,35 @@ namespace transport { } + bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + { + static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes + uint8_t h[64], ck[33]; + SHA256 ((const uint8_t *)protocolName, 32, h); + memcpy (ck, h, 32); + // h = SHA256(h || rs) + memcpy (h + 32, rs, 32); + SHA256 (h, 64, h); + // h = SHA256(h || pub) + memcpy (h + 32, pub, 32); + SHA256 (h, 64, h); + // x25519 between rs and priv + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->Mul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + BN_CTX_free (ctx); + // temp_key = HMAC-SHA256(ck, input_key_material) + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), ck, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) + inputKeyMaterial[0] = 1; + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, ck, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + ck[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, ck, 33, derived, &len); + return true; + } + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { uint8_t key[32]; diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 6dfea8ae..11bb2674 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -19,6 +19,7 @@ namespace transport private: + bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (const uint8_t * iv); From a70d0edf2e8b80f7553c709c07aa93f96e36082a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 16:15:33 -0400 Subject: [PATCH 066/115] encrypt SessionRequest options block --- libi2pd/NTCP2.cpp | 16 ++++++++++++---- libi2pd/NTCP2.h | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e6072207..8b33eb0d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -24,8 +24,8 @@ namespace transport { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; - SHA256 ((const uint8_t *)protocolName, 32, h); - memcpy (ck, h, 32); + memcpy (ck, protocolName, 32); + SHA256 ((const uint8_t *)protocolName, 32, h); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); SHA256 (h, 64, h); @@ -60,7 +60,7 @@ namespace transport BN_CTX_free (ctx); } - void NTCP2Session::SendSessionRequest (const uint8_t * iv) + void NTCP2Session::SendSessionRequest (const uint8_t * iv, const uint8_t * rs) { i2p::crypto::AESAlignedBuffer<32> x; CreateEphemeralKey (x); @@ -68,7 +68,15 @@ namespace transport i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (iv); - encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + // encryption key for next block + uint8_t key[32]; + KeyDerivationFunction (rs, x, key); + // options + uint8_t options[32]; + // TODO: fill 16 bytes options + i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first + i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 11bb2674..52319db3 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -21,7 +21,7 @@ namespace transport bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); - void SendSessionRequest (const uint8_t * iv); + void SendSessionRequest (const uint8_t * iv, const uint8_t * rs); private: From 4f23d7b7df6b62b85c780e57cf4aad1fa138edb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jun 2018 11:51:34 -0400 Subject: [PATCH 067/115] recognize routers with NTCP2 --- libi2pd/RouterInfo.cpp | 30 +++++++++++++++++++++++++----- libi2pd/RouterInfo.h | 12 +++++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index e3f4d2d4..87f16346 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -244,6 +244,18 @@ namespace data } else if (!strcmp (key, "caps")) ExtractCaps (value); + else if (!strcmp (key, "s")) // ntcp2 static key + { + if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); + supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; + Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32); + } + else if (!strcmp (key, "i")) // ntcp2 iv + { + if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); + supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; + Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); + } else if (key[0] == 'i') { // introducers @@ -735,6 +747,14 @@ namespace data return m_SupportedTransports & (eSSUV4 | eSSUV6); } + bool RouterInfo::IsNTCP2 (bool v4only) const + { + if (v4only) + return m_SupportedTransports & eNTCP2V4; + else + return m_SupportedTransports & (eNTCP2V4 | eNTCP2V6); + } + bool RouterInfo::IsV6 () const { return m_SupportedTransports & (eNTCPV6 | eSSUV6); @@ -742,19 +762,19 @@ namespace data bool RouterInfo::IsV4 () const { - return m_SupportedTransports & (eNTCPV4 | eSSUV4); + return m_SupportedTransports & (eNTCPV4 | eSSUV4 | eNTCP2V4); } void RouterInfo::EnableV6 () { if (!IsV6 ()) - m_SupportedTransports |= eNTCPV6 | eSSUV6; + m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6; } void RouterInfo::EnableV4 () { if (!IsV4 ()) - m_SupportedTransports |= eNTCPV4 | eSSUV4; + m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4; } @@ -762,7 +782,7 @@ namespace data { if (IsV6 ()) { - m_SupportedTransports &= ~(eNTCPV6 | eSSUV6); + m_SupportedTransports &= ~(eNTCPV6 | eSSUV6 | eNTCP2V6); for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; @@ -778,7 +798,7 @@ namespace data { if (IsV4 ()) { - m_SupportedTransports &= ~(eNTCPV4 | eSSUV4); + m_SupportedTransports &= ~(eNTCPV4 | eSSUV4 | eNTCP2V4); for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 09e2c015..1125bdef 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -48,7 +48,9 @@ namespace data eNTCPV4 = 0x01, eNTCPV6 = 0x02, eSSUV4 = 0x04, - eSSUV6 = 0x08 + eSSUV6 = 0x08, + eNTCP2V4 = 0x10, + eNTCP2V6 = 0x20 }; enum Caps @@ -88,6 +90,12 @@ namespace data std::vector introducers; }; + struct NTCP2Ext + { + uint8_t staticKey[32]; + uint8_t iv[16]; + }; + struct Address { TransportStyle transportStyle; @@ -97,6 +105,7 @@ namespace data uint64_t date; uint8_t cost; std::unique_ptr ssu; // not null for SSU + std::unique_ptr ntcp2; // not null for NTCP2 bool IsCompatible (const boost::asio::ip::address& other) const { @@ -144,6 +153,7 @@ namespace data bool IsReachable () const { return m_Caps & Caps::eReachable; }; bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; + bool IsNTCP2 (bool v4only = true) const; bool IsV6 () const; bool IsV4 () const; void EnableV6 (); From 5cb81f8532b840da3ebf2b9c7c9b3d21ebc81169 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jun 2018 15:38:18 -0400 Subject: [PATCH 068/115] send SessionRequest message --- libi2pd/NTCP2.cpp | 60 ++++++++++++++++++++++++++++++++++++++++------- libi2pd/NTCP2.h | 29 +++++++++++++++++++++-- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8b33eb0d..ac2805e0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include "Log.h" +#include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" #include "ChaCha20.h" @@ -11,13 +14,23 @@ namespace i2p { namespace transport { - NTCP2Session::NTCP2Session (std::shared_ptr in_RemoteRouter): - TransportSession (in_RemoteRouter, 30) + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): + TransportSession (in_RemoteRouter, 30), + m_Server (server), m_Socket (m_Server.GetService ()), m_SessionRequestBuffer (nullptr) { + auto addr = in_RemoteRouter->GetNTCPAddress (); + if (addr->ntcp2) + { + memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_RemoteIV, addr->ntcp2->iv, 16); + } + else + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } NTCP2Session::~NTCP2Session () { + delete[] m_SessionRequestBuffer; } bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) @@ -60,24 +73,55 @@ namespace transport BN_CTX_free (ctx); } - void NTCP2Session::SendSessionRequest (const uint8_t * iv, const uint8_t * rs) + void NTCP2Session::SendSessionRequest () { i2p::crypto::AESAlignedBuffer<32> x; CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (iv); + encryption.SetIV (m_RemoteIV); encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); // encryption key for next block uint8_t key[32]; - KeyDerivationFunction (rs, x, key); - // options - uint8_t options[32]; - // TODO: fill 16 bytes options + KeyDerivationFunction (m_RemoteStaticKey, x, key); + // fill options + uint8_t options[32]; // actual options size is 16 bytes + memset (options, 0, 16); + htobe16buf (options, 2); // ver + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + htobe16buf (options + 2, paddingLength); // padLen + htobe16buf (options + 4, 0); // m3p2Len TODO: + // 2 bytes reserved + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA + // 4 bytes reserved + // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt + // create buffer + m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + memcpy (m_SessionRequestBuffer, x, 32); + memcpy (m_SessionRequestBuffer + 32, options, 32); + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), + 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) + { + (void) bytes_transferred; + delete[] m_SessionRequestBuffer; m_SessionRequestBuffer = nullptr; + if (ecode) + { + LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + } + } + + void NTCP2Session::ClientLogin () + { + SendSessionRequest (); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 52319db3..059f46c5 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -3,6 +3,7 @@ #include #include +#include #include "RouterInfo.h" #include "TransportSession.h" @@ -10,22 +11,46 @@ namespace i2p { namespace transport { + class NTCP2Server; class NTCP2Session: public TransportSession, public std::enable_shared_from_this { public: - NTCP2Session (std::shared_ptr in_RemoteRouter = nullptr); // TODO + NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO ~NTCP2Session (); + boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + + void ClientLogin (); // Alice + private: bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); - void SendSessionRequest (const uint8_t * iv, const uint8_t * rs); + void SendSessionRequest (); + + void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: + NTCP2Server& m_Server; + boost::asio::ip::tcp::socket m_Socket; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key + uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; + uint8_t * m_SessionRequestBuffer; + }; + + class NTCP2Server + { + public: + + NTCP2Server () {}; + ~NTCP2Server () {} ; + boost::asio::io_service& GetService () { return m_Service; }; + + private: + + boost::asio::io_service m_Service; }; } } From 74c0b729c22b181c42b5e38ab342d99f51e528ac Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 12:29:30 -0400 Subject: [PATCH 069/115] connect to NTCP2 --- libi2pd/NTCP2.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++-- libi2pd/NTCP2.h | 28 +++++++++--- 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ac2805e0..6b21e900 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -16,7 +16,9 @@ namespace transport { NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, 30), - m_Server (server), m_Socket (m_Server.GetService ()), m_SessionRequestBuffer (nullptr) + m_Server (server), m_Socket (m_Server.GetService ()), + m_IsEstablished (false), m_IsTerminated (false), + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -31,9 +33,21 @@ namespace transport NTCP2Session::~NTCP2Session () { delete[] m_SessionRequestBuffer; + delete[] m_SessionCreatedBuffer; } - bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::Terminate () + { + if (!m_IsTerminated) + { + m_IsTerminated = true; + m_IsEstablished = false; + m_Socket.close (); + LogPrint (eLogDebug, "NTCP2: session terminated"); + } + } + + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -84,7 +98,7 @@ namespace transport encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); // encryption key for next block uint8_t key[32]; - KeyDerivationFunction (m_RemoteStaticKey, x, key); + KeyDerivationFunction1 (m_RemoteStaticKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -115,13 +129,102 @@ namespace transport if (ecode) { LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + Terminate (); } + else + { + m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, sizeof (56)), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } + + void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; + if (ecode) + LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message ()); + Terminate (); // TODO: continue } void NTCP2Session::ClientLogin () { SendSessionRequest (); } + + NTCP2Server::NTCP2Server (): + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) + { + } + + NTCP2Server::~NTCP2Server () + { + Stop (); + } + + void NTCP2Server::Start () + { + if (!m_IsRunning) + { + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + } + } + + void NTCP2Server::Stop () + { + if (m_IsRunning) + { + m_IsRunning = false; + 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 ()); + } + } + } + + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) + { + LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); + m_Service.post([this, address, port, conn]() + { + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + }); + } + + void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn) + { + if (ecode) + { + LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ()); + conn->Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ()); + conn->ClientLogin (); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 059f46c5..a4f30920 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -18,6 +18,7 @@ namespace transport NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO ~NTCP2Session (); + void Terminate (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -25,32 +26,49 @@ namespace transport private: - bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: NTCP2Server& m_Server; boost::asio::ip::tcp::socket m_Socket; + bool m_IsEstablished, m_IsTerminated; + uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; - uint8_t * m_SessionRequestBuffer; + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; }; class NTCP2Server { public: - NTCP2Server () {}; - ~NTCP2Server () {} ; + NTCP2Server (); + ~NTCP2Server (); + + void Start (); + void Stop (); + 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 HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); + + private: + + bool m_IsRunning; + std::thread * m_Thread; boost::asio::io_service m_Service; + boost::asio::io_service::work m_Work; }; } } From 7cdb021a1fb3e54e4526981399bfa7db9fb103a0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 14:05:30 -0400 Subject: [PATCH 070/115] pass correct nonce to chacha20 --- libi2pd/NTCP2.cpp | 13 ++++++++++--- libi2pd/NTCP2.h | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6b21e900..f3baa06c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -47,6 +47,11 @@ namespace transport } } + void NTCP2Session::Done () + { + m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes @@ -111,7 +116,9 @@ namespace transport // 4 bytes reserved // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first - i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt + uint8_t nonce[12]; + memset (nonce, 0, 12); + i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt // create buffer m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; memcpy (m_SessionRequestBuffer, x, 32); @@ -145,7 +152,7 @@ namespace transport (void) bytes_transferred; delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; if (ecode) - LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message ()); + LogPrint (eLogInfo, "NTCP2: SessionCreated read error: ", ecode.message ()); Terminate (); // TODO: continue } @@ -205,7 +212,7 @@ namespace transport void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { - LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); + LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); m_Service.post([this, address, port, conn]() { conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index a4f30920..ca36d37b 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "RouterInfo.h" #include "TransportSession.h" @@ -16,13 +17,15 @@ namespace transport { public: - NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO + NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCP2Session (); void Terminate (); + void Done (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ClientLogin (); // Alice + void SendI2NPMessages (const std::vector >& msgs) {}; // TODO private: From 7f3127ac893406a2a09fce63d8dca41e18de9f72 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 14:32:15 -0400 Subject: [PATCH 071/115] pass unencrypted X to KDF --- libi2pd/NTCP2.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f3baa06c..44c32324 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -94,13 +94,18 @@ namespace transport void NTCP2Session::SendSessionRequest () { - i2p::crypto::AESAlignedBuffer<32> x; + // create buffer and fill padding + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // generate key pair (X) + uint8_t x[32]; CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_RemoteIV); - encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + encryption.Encrypt (x, 32, m_SessionRequestBuffer); // encryption key for next block uint8_t key[32]; KeyDerivationFunction1 (m_RemoteStaticKey, x, key); @@ -108,7 +113,6 @@ namespace transport uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); htobe16buf (options, 2); // ver - auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 4, 0); // m3p2Len TODO: // 2 bytes reserved @@ -117,13 +121,9 @@ namespace transport // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first uint8_t nonce[12]; - memset (nonce, 0, 12); + memset (nonce, 0, 12); // set nonce to zero i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt - // create buffer - m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; - memcpy (m_SessionRequestBuffer, x, 32); memcpy (m_SessionRequestBuffer + 32, options, 32); - RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); From a8278fc78bba272518aaffe573a7cd4870e0091b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 15:33:48 -0400 Subject: [PATCH 072/115] router's NTCP2 private keys --- libi2pd/Config.cpp | 1 + libi2pd/RouterContext.cpp | 31 +++++++++++++++++++++++++++++++ libi2pd/RouterContext.h | 11 +++++++++++ 3 files changed, 43 insertions(+) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 126de7fc..a7bc305c 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -59,6 +59,7 @@ namespace config { ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") + ("ntcp2", value()->zero_tokens()->default_value(false), "Enable NTCP2 (experimental)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a82ace85..b0f1aa51 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1,4 +1,5 @@ #include +#include #include "Config.h" #include "Crypto.h" #include "Timestamp.h" @@ -98,6 +99,16 @@ namespace i2p m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); } + void RouterContext::NewNTCP2Keys () + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + RAND_bytes (m_NTCP2Keys->staticKey, 32); + RAND_bytes (m_NTCP2Keys->iv, 16); + // save + std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out); + fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + void RouterContext::SetStatus (RouterStatus status) { if (status != m_Status) @@ -429,6 +440,26 @@ namespace i2p if (IsUnreachable ()) SetReachable (); // we assume reachable until we discover firewall through peer tests + // read NTCP2 + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + if (ntcp2) + { + std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); + if (n2k) + { + n2k.seekg (0, std::ios::end); + len = fk.tellg(); + n2k.seekg (0, std::ios::beg); + if (len == sizeof (NTCP2PrivateKeys)) + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + } + if (!m_NTCP2Keys) + NewNTCP2Keys (); + } + return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 4bd324f5..02c0156b 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -14,6 +14,7 @@ namespace i2p { const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; + const char NTCP2_KEYS[] = "ntcp2.keys"; const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes enum RouterStatus @@ -32,6 +33,14 @@ namespace i2p class RouterContext: public i2p::garlic::GarlicDestination { + private: + + struct NTCP2PrivateKeys + { + uint8_t staticKey[32]; + uint8_t iv[16]; + }; + public: RouterContext (); @@ -108,6 +117,7 @@ namespace i2p void CreateNewRouter (); void NewRouterInfo (); void UpdateRouterInfo (); + void NewNTCP2Keys (); bool Load (); void SaveKeys (); @@ -125,6 +135,7 @@ namespace i2p RouterError m_Error; int m_NetID; std::mutex m_GarlicMutex; + std::unique_ptr m_NTCP2Keys; }; extern RouterContext context; From 046a80cfe4d35b0ab8a4e17753812ef555429ba6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 12:42:20 -0400 Subject: [PATCH 073/115] scalar multiplication for x25519 --- libi2pd/Ed25519.cpp | 101 +++++++++++++++++++++++++++++++++++++++++--- libi2pd/Ed25519.h | 6 ++- libi2pd/NTCP2.cpp | 5 +-- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 8258d33c..f8fdaae1 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,12 +411,103 @@ namespace crypto } } - void Ed25519::Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + BIGNUM * Ed25519::ScalarMul (const BIGNUM * p, const BIGNUM * n, BN_CTX * ctx) const { - auto P = DecodePublicKey (p, ctx); - BIGNUM * e1 = DecodeBN<32> (e); - EncodePublicKey (Mul (P, e1, ctx), buf, ctx); - BN_free (e1); + BN_CTX_start (ctx); + auto x1 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x2 = BN_CTX_get (ctx); BN_one (x2); + auto z2 = BN_CTX_get (ctx); BN_zero (z2); + auto x3 = BN_CTX_get (ctx); BN_copy (x1, p); + auto z3 = BN_CTX_get (ctx); BN_one (z3); + auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); + auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); + auto b = BN_CTX_get (ctx); auto bb = BN_CTX_get (ctx); + auto e = BN_CTX_get (ctx); auto c = BN_CTX_get (ctx); + auto d = BN_CTX_get (ctx); + auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); + auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); + unsigned int swap = 0; + auto bits = BN_num_bits (n); + while(bits) + { + --bits; + auto k_t = BN_is_bit_set(n, bits) ? 1 : 0; + swap ^= k_t; + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + swap = k_t; + // a = x2 + z2 + BN_mod_add(a, x2, z2, q, ctx); + // aa = a^2 + BN_mod_sqr(aa, a, q, ctx); + // b = x2 - z2 + BN_mod_sub(b, x2, z2, q, ctx); + // bb = b^2 + BN_mod_sqr(bb, b, q, ctx); + // e = aa - bb + BN_mod_sub(e, aa, bb, q, ctx); + // c = x3 + z3 + BN_mod_add(c, x3, z3, q, ctx); + // d = x3 - z3 + BN_mod_sub(d, x3, z3, q, ctx); + // da = d * a + BN_mod_mul(da, d, a, q, ctx); + // cb = c * b + BN_mod_mul(cb, c, b, q, ctx); + // x3 = ( da + cb )^2 + BN_mod_add(tmp1, da, cb, q, ctx); + BN_mod_sqr(x3, tmp1, q, ctx); + // z3 == x1 * (da - cb)^2 + BN_mod_sub(tmp1, da, cb, q, ctx); + BN_mod_sqr(tmp2, tmp1, q, ctx); + BN_mod_mul(z3, x1, tmp2, q, ctx); + // x2 = aa * bb + BN_mod_mul(x2, aa, bb, q, ctx); + // z2 = e * (aa + a24 * e) + BN_mod_mul(tmp1, a24, e, q, ctx); + BN_mod_add(tmp2, aa, tmp1, q, ctx); + BN_mod_mul(z2, e, tmp2, q, ctx); + } + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + // x2 * (z2 ^ (q - 2)) + BN_set_word(tmp1, 2); + BN_sub(tmp2, q, tmp1); + BN_mod_exp(tmp1, z2, tmp2, q, ctx); + BIGNUM * res = BN_new (); // not from ctx + BN_mod_mul(res, x2, tmp1, q, ctx); + BN_CTX_end (ctx); + return res; + } + + void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM * p1 = DecodeBN<32> (p); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); + } + + void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); } void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index cbf14bfd..fc23a457 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -75,7 +75,8 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; - void Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number + void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 + void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; @@ -99,6 +100,9 @@ namespace crypto BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; + // for x25519 + BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; + private: BIGNUM * q, * l, * d, * I; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 44c32324..43ccc2dd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -67,7 +67,7 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->Mul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); // temp_key = HMAC-SHA256(ck, input_key_material) uint8_t tempKey[32]; unsigned int len; @@ -87,8 +87,7 @@ namespace transport RAND_bytes (key, 32); i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); BN_CTX * ctx = BN_CTX_new (); - auto publicKey = i2p::crypto::GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); - i2p::crypto::GetEd25519 ()->EncodePublicKey (publicKey, pub, ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_ExpandedPrivateKey, pub, ctx); BN_CTX_free (ctx); } From 3b46e9f3510f0579ac37eca299bb7937eb587cb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 14:55:40 -0400 Subject: [PATCH 074/115] fixed typo --- libi2pd/Ed25519.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index f8fdaae1..05721d80 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,13 +411,13 @@ namespace crypto } } - BIGNUM * Ed25519::ScalarMul (const BIGNUM * p, const BIGNUM * n, BN_CTX * ctx) const + BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const { BN_CTX_start (ctx); - auto x1 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x1 = BN_CTX_get (ctx); BN_copy (x1, u); auto x2 = BN_CTX_get (ctx); BN_one (x2); auto z2 = BN_CTX_get (ctx); BN_zero (z2); - auto x3 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); auto z3 = BN_CTX_get (ctx); BN_one (z3); auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); @@ -427,11 +427,11 @@ namespace crypto auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); unsigned int swap = 0; - auto bits = BN_num_bits (n); + auto bits = BN_num_bits (k); while(bits) { --bits; - auto k_t = BN_is_bit_set(n, bits) ? 1 : 0; + auto k_t = BN_is_bit_set(k, bits) ? 1 : 0; swap ^= k_t; if (swap) { From 7fa5b06359ac30c2006af2e67ce54e1680c4c244 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 18:29:06 -0400 Subject: [PATCH 075/115] x25519 unti test --- tests/Makefile | 7 +++++-- tests/test-x25519.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/test-x25519.cpp diff --git a/tests/Makefile b/tests/Makefile index f769ad35..4f4c895c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -TESTS = test-gost test-gost-sig test-base-64 +TESTS = test-gost test-gost-sig test-base-64 test-x25519 all: $(TESTS) run @@ -13,7 +13,10 @@ test-base-%: ../libi2pd/Base.cpp test-base-%.cpp test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Signature.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp +test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp ../libi2pd/Log.cpp test-gost-sig.cpp + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system + +test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system run: $(TESTS) diff --git a/tests/test-x25519.cpp b/tests/test-x25519.cpp new file mode 100644 index 00000000..9f249dbd --- /dev/null +++ b/tests/test-x25519.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +#include "Ed25519.h" + +const uint8_t k[32] = +{ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, + 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, + 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 +}; + +const uint8_t u[32] = +{ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, + 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, + 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c +}; + +uint8_t p[32] = +{ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, + 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, + 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 +}; + +int main () +{ + 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); +} + From bf1e1ad457259db4148065305b95101c7cdfce96 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 10:49:14 -0400 Subject: [PATCH 076/115] eliminate extra dependencies --- tests/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 4f4c895c..38080a32 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread +CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files TESTS = test-gost test-gost-sig test-base-64 test-x25519 @@ -13,10 +13,10 @@ test-base-%: ../libi2pd/Base.cpp test-base-%.cpp test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp ../libi2pd/Log.cpp test-gost-sig.cpp +test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system -test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp test-x25519.cpp +test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system run: $(TESTS) From df60e787661c07ad92144c72c0da872e78b556e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 11:41:46 -0400 Subject: [PATCH 077/115] AEAD/Chacha20/Poly1305 encryption --- libi2pd/Crypto.cpp | 29 +++++++++++++++++++++++++++++ libi2pd/Crypto.h | 4 ++++ libi2pd/I2PEndian.h | 13 +++++++++++++ libi2pd/NTCP2.cpp | 14 +++++--------- libi2pd/NTCP2.h | 2 +- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 8ba99a15..5e8ba855 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,6 +8,9 @@ #include #include "TunnelBase.h" #include +#include "I2PEndian.h" +#include "ChaCha20.h" +#include "Poly1305.h" #include "Log.h" #include "Crypto.h" @@ -1057,6 +1060,32 @@ namespace crypto } } +// AEAD/ChaCha20/Poly1305 + + size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + if (msgLen + 16 < len) return 0; + // generate one time poly key + uint8_t polyKey[64]; + memset(polyKey, 0, sizeof(polyKey)); + chacha20 (polyKey, 64, nonce, key, 0); + // encrypt data + memcpy (buf, msg, msgLen); + chacha20 (buf, msgLen, nonce, key, 1); + // create Poly1305 message + std::vector polyMsg(adLen + msgLen + 16); + size_t offset = 0; + memcpy (polyMsg.data (), ad, adLen); offset += adLen; + memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + htole64buf (polyMsg.data () + offset, adLen); offset += 8; + htole64buf (polyMsg.data () + offset, msgLen); offset += 8; + // calculate Poly1305 tag and write in after encrypted data + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)key, polyMsg.data (), offset); + return msgLen + 16; + } + +// init and terminate + /* std::vector > m_OpenSSLMutexes; static void OpensslLockingCallback(int mode, int type, const char * file, int line) { diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 859f2d97..0600c48c 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -252,6 +252,10 @@ namespace crypto CBCDecryption m_LayerDecryption; }; +// AEAD/ChaCha20/Poly1305 + size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + +// init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); } diff --git a/libi2pd/I2PEndian.h b/libi2pd/I2PEndian.h index d2250768..0798f688 100644 --- a/libi2pd/I2PEndian.h +++ b/libi2pd/I2PEndian.h @@ -113,7 +113,20 @@ inline void htobe64buf(void *buf, uint64_t big64) htobuf64(buf, htobe64(big64)); } +inline void htole16buf(void *buf, uint16_t big16) +{ + htobuf16(buf, htole16(big16)); +} +inline void htole32buf(void *buf, uint32_t big32) +{ + htobuf32(buf, htole32(big32)); +} + +inline void htole64buf(void *buf, uint64_t big64) +{ + htobuf64(buf, htole64(big64)); +} #endif // I2PENDIAN_H__ diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 43ccc2dd..b3794354 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -6,8 +6,6 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" -#include "ChaCha20.h" -#include "Poly1305.h" #include "NTCP2.h" namespace i2p @@ -52,7 +50,7 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -63,7 +61,7 @@ namespace transport SHA256 (h, 64, h); // h = SHA256(h || pub) memcpy (h + 32, pub, 32); - SHA256 (h, 64, h); + SHA256 (h, 64, ad); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); @@ -106,8 +104,8 @@ namespace transport encryption.SetIV (m_RemoteIV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); // encryption key for next block - uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key); + uint8_t key[32], ad[32]; + KeyDerivationFunction1 (m_RemoteStaticKey, x, key, ad); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -118,11 +116,9 @@ namespace transport htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved // sign and encrypt options - i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt - memcpy (m_SessionRequestBuffer + 32, options, 32); + i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, ad, 32, key, nonce, m_SessionRequestBuffer + 32, 32); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index ca36d37b..8cdf6073 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,7 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); From 6b9061515fcc0da9c0e24fd770bf215331a576e2 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 12:25:32 -0400 Subject: [PATCH 078/115] AEAD/ChaCha20/Poly1305 test added --- libi2pd/Crypto.cpp | 17 ++++++++-- tests/Makefile | 5 ++- tests/test-aeadchacha20poly1305.cpp | 49 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/test-aeadchacha20poly1305.cpp diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 5e8ba855..6d52a6c1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1073,10 +1073,23 @@ namespace crypto memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); // create Poly1305 message - std::vector polyMsg(adLen + msgLen + 16); + std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; - memcpy (polyMsg.data (), ad, adLen); offset += adLen; + uint8_t padding[16]; memset (padding, 0, 16); + memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data + auto rem = adLen & 0x0F; // %16 + if (rem) + { + // padding1 + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + rem = msgLen & 0x0F; // %16 + if (rem) + { + // padding2 + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; // calculate Poly1305 tag and write in after encrypted data diff --git a/tests/Makefile b/tests/Makefile index 38080a32..498cff17 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files -TESTS = test-gost test-gost-sig test-base-64 test-x25519 +TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 all: $(TESTS) run @@ -19,6 +19,9 @@ test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cp test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system +test-aeadchacha20poly1305: ../libi2pd/Crypto.cpp ../libi2pd/ChaCha20.cpp ../libi2pd/Poly1305.cpp test-aeadchacha20poly1305.cpp + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system + run: $(TESTS) @for TEST in $(TESTS); do ./$$TEST ; done diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp new file mode 100644 index 00000000..cb9ed5c3 --- /dev/null +++ b/tests/test-aeadchacha20poly1305.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +#include "Crypto.h" + +char text[] = "Ladies and Gentlemen of the class of '99: If I could offer you " +"only one tip for the future, sunscreen would be it."; // 114 bytes + +uint8_t key[32] = +{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f +}; + +uint8_t ad[12] = +{ + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 +}; + +uint8_t nonce[12] = +{ + 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 +}; + +uint8_t tag[16] = +{ + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 +}; + +uint8_t encrypted[114] = +{ + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 +}; + +int main () +{ + uint8_t buf[114+16]; + i2p::crypto::AEADChaCha20Poly1305Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); + assert (memcmp (buf, encrypted, 114) == 0); + assert(memcmp (buf + 114, tag, 16) == 0); +} From 966256ac325d500b04e1e746414aa89a66b2e0ac Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 12:58:32 -0400 Subject: [PATCH 079/115] correct Poly1305 calculation --- libi2pd/Crypto.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 6d52a6c1..0073faee 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,6 +1081,7 @@ namespace crypto if (rem) { // padding1 + rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data @@ -1088,12 +1089,14 @@ namespace crypto if (rem) { // padding2 + rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; + // calculate Poly1305 tag and write in after encrypted data - Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)key, polyMsg.data (), offset); + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); return msgLen + 16; } From ee0ae0b74bca554fe15b8e9d8c231e6f8f991758 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 14:56:51 -0400 Subject: [PATCH 080/115] decrypt Y for NTCP2 --- libi2pd/Crypto.h | 2 ++ libi2pd/NTCP2.cpp | 42 ++++++++++++++++++++++++++---------------- libi2pd/NTCP2.h | 4 ++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 0600c48c..c124a200 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -181,6 +181,7 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes + void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_LastBlock, 16); }; void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); @@ -203,6 +204,7 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes + void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_IV, 16); }; void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b3794354..474ad67d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -22,7 +22,7 @@ namespace transport if (addr->ntcp2) { memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_RemoteIV, addr->ntcp2->iv, 16); + memcpy (m_IV, addr->ntcp2->iv, 16); } else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); @@ -50,7 +50,7 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad) + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -61,7 +61,7 @@ namespace transport SHA256 (h, 64, h); // h = SHA256(h || pub) memcpy (h + 32, pub, 32); - SHA256 (h, 64, ad); + SHA256 (h, 64, m_H); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); @@ -101,24 +101,25 @@ namespace transport // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_RemoteIV); + encryption.SetIV (m_IV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); + encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block - uint8_t key[32], ad[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key, ad); + uint8_t key[32]; + KeyDerivationFunction1 (m_RemoteStaticKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); htobe16buf (options, 2); // ver htobe16buf (options + 2, paddingLength); // padLen - htobe16buf (options + 4, 0); // m3p2Len TODO: + htobe16buf (options + 4, 550); // m3p2Len TODO: // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved - // sign and encrypt options + // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, ad, 32, key, nonce, m_SessionRequestBuffer + 32, 32); + i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -127,28 +128,37 @@ namespace transport void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { (void) bytes_transferred; - delete[] m_SessionRequestBuffer; m_SessionRequestBuffer = nullptr; if (ecode) { - LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); Terminate (); } else { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, sizeof (56)), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 56), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - (void) bytes_transferred; - delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; if (ecode) - LogPrint (eLogInfo, "NTCP2: SessionCreated read error: ", ecode.message ()); - Terminate (); // TODO: continue + { + LogPrint (eLogWarning, "NTCP2: SessionCreated read error: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated received ", bytes_transferred); + uint8_t y[32]; + // decrypt Y + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); + decryption.SetIV (m_IV); + decryption.Decrypt (m_SessionCreatedBuffer, 32, y); + } } void NTCP2Session::ClientLogin () diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 8cdf6073..456f9d3e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,7 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad); // for SessionRequest + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -43,7 +43,7 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32]; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; }; From 5447259e1a2cc7b29c4fc4993a85be3bb145b1fd Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 16:16:23 -0400 Subject: [PATCH 081/115] AEAD/ChaCha20/Poly1305 decryption and SessionCreate prcessing --- libi2pd/Crypto.cpp | 23 ++++++--- libi2pd/Crypto.h | 2 +- libi2pd/NTCP2.cpp | 73 ++++++++++++++++++++++++----- libi2pd/NTCP2.h | 7 ++- tests/test-aeadchacha20poly1305.cpp | 9 +++- 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 0073faee..bdcf5acd 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1062,9 +1062,9 @@ namespace crypto // AEAD/ChaCha20/Poly1305 - size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (msgLen + 16 < len) return 0; + if (encrypt && msgLen + 16 < len) return 0; // generate one time poly key uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); @@ -1072,6 +1072,7 @@ namespace crypto // encrypt data memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); + // create Poly1305 message std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; @@ -1084,7 +1085,7 @@ namespace crypto rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } - memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data rem = msgLen & 0x0F; // %16 if (rem) { @@ -1095,9 +1096,19 @@ namespace crypto htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; - // calculate Poly1305 tag and write in after encrypted data - Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); - return msgLen + 16; + if (encrypt) + { + // calculate Poly1305 tag and write in after encrypted data + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); + } + else + { + uint32_t tag[8]; + // calculate Poly1305 tag + Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); + if (memcmp (tag, msg + msgLen, 16)) return false; // compare with provided + } + return true; } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index c124a200..af4ec1f8 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -255,7 +255,7 @@ namespace crypto }; // AEAD/ChaCha20/Poly1305 - size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag // init and terminate void InitCrypto (bool precomputation); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 474ad67d..64636433 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "Log.h" #include "I2PEndian.h" #include "Crypto.h" @@ -50,11 +51,11 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes - uint8_t h[64], ck[33]; - memcpy (ck, protocolName, 32); + uint8_t h[64]; + memcpy (m_CK, protocolName, 32); SHA256 ((const uint8_t *)protocolName, 32, h); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); @@ -69,14 +70,43 @@ namespace transport BN_CTX_free (ctx); // temp_key = HMAC-SHA256(ck, input_key_material) uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), ck, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) + HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, ck, &len); + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - ck[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, ck, 33, derived, &len); - return true; + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + } + + void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + { + uint8_t h[64]; + memcpy (h, m_H, 32); + memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload + SHA256 (h, 64, m_H); + int paddingLength = sessionRequestLen - 64; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), m_H, 32); + memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); + SHA256 (h1.data (), paddingLength + 32, m_H); + } + // x25519 between remote pub and priv + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); + BN_CTX_free (ctx); + // 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)) + inputKeyMaterial[0] = 1; + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -93,7 +123,8 @@ namespace transport { // create buffer and fill padding auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + m_SessionRequestBufferLen = paddingLength + 64; + m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // generate key pair (X) uint8_t x[32]; @@ -119,9 +150,9 @@ 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::AEADChaCha20Poly1305Encrypt (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32); + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -151,13 +182,29 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionCreated received ", bytes_transferred); + LogPrint (eLogInfo, "NTCP2: SessionCreated received ", bytes_transferred); uint8_t y[32]; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, y); + // decryption key for next block + uint8_t key[32]; + KeyDerivationFunction2 (y, m_SessionRequestBuffer, m_SessionRequestBufferLen, key); + // decrypt and verify MAC + uint8_t payload[8]; + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, key, nonce, payload, 8, false)) // decrypt + { + // TODO: + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed "); + Terminate (); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 456f9d3e..b7e83f26 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,9 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -43,8 +45,9 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32]; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; + size_t m_SessionRequestBufferLen; }; class NTCP2Server diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp index cb9ed5c3..dcd4b4d6 100644 --- a/tests/test-aeadchacha20poly1305.cpp +++ b/tests/test-aeadchacha20poly1305.cpp @@ -43,7 +43,12 @@ uint8_t encrypted[114] = int main () { uint8_t buf[114+16]; - i2p::crypto::AEADChaCha20Poly1305Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); + // test encryption + i2p::crypto::AEADChaCha20Poly1305 ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16, true); assert (memcmp (buf, encrypted, 114) == 0); - assert(memcmp (buf + 114, tag, 16) == 0); + assert (memcmp (buf + 114, tag, 16) == 0); + // test decryption + uint8_t buf1[114]; + assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false)); + assert (memcmp (buf1, text, 114) == 0); } From 6b37a41e007fa81be0ce00cdcc6b50e921630e4c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jun 2018 10:45:25 -0400 Subject: [PATCH 082/115] correct ad calculation for SessionCreated --- libi2pd/NTCP2.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 64636433..f2675276 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -84,15 +84,18 @@ namespace transport uint8_t h[64]; memcpy (h, m_H, 32); memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, m_H); + SHA256 (h, 64, h); int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { std::vector h1(paddingLength + 32); - memcpy (h1.data (), m_H, 32); + memcpy (h1.data (), h, 32); memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, m_H); + SHA256 (h1.data (), paddingLength + 32, h); } + memcpy (h + 32, pub, 32); + SHA256 (h, 64, m_H); + // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); From 2bd7a92d20306a5ff99ebc069a634eb18f40b042 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jun 2018 15:29:36 -0400 Subject: [PATCH 083/115] send SessionConfirmed --- libi2pd/NTCP2.cpp | 128 ++++++++++++++++++++++++++++++++++++---------- libi2pd/NTCP2.h | 11 ++-- 2 files changed, 109 insertions(+), 30 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f2675276..2dd18960 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -17,7 +17,7 @@ namespace transport TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr) + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -33,6 +33,7 @@ namespace transport { delete[] m_SessionRequestBuffer; delete[] m_SessionCreatedBuffer; + delete[] m_SessionConfirmedBuffer; } void NTCP2Session::Terminate () @@ -51,6 +52,19 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } + void NTCP2Session::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) + { + // 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, derived, &len); + } + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes @@ -68,15 +82,7 @@ namespace transport BN_CTX * ctx = BN_CTX_new (); i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); - // 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)) - inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + MixKey (inputKeyMaterial, derived); } void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) @@ -101,15 +107,16 @@ namespace transport BN_CTX * ctx = BN_CTX_new (); i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); BN_CTX_free (ctx); - // 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)) - inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Session::KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived) + { + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (m_Y, staticPrivKey, inputKeyMaterial, ctx); + BN_CTX_free (ctx); + MixKey (inputKeyMaterial, derived); } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -185,23 +192,30 @@ namespace transport } else { - LogPrint (eLogInfo, "NTCP2: SessionCreated received ", bytes_transferred); - uint8_t y[32]; + LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); + m_SessionCreatedBufferLen = 56; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, y); - // decryption key for next block - uint8_t key[32]; - KeyDerivationFunction2 (y, m_SessionRequestBuffer, m_SessionRequestBufferLen, key); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); + // decryption key for next block (m_K) + KeyDerivationFunction2 (m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC uint8_t payload[8]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, key, nonce, payload, 8, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, m_K, nonce, payload, 8, false)) // decrypt { - // TODO: + uint16_t paddingLen = bufbe16toh(payload); + LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); + if (paddingLen > 0) + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 56, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + SendSessionConfirmed (); } else { @@ -211,6 +225,66 @@ namespace transport } } + void NTCP2Session::HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionCreated padding read error: ", ecode.message ()); + Terminate (); + } + else + { + m_SessionCreatedBufferLen += bytes_transferred; + SendSessionConfirmed (); + } + } + + void NTCP2Session::SendSessionConfirmed () + { + // update AD + uint8_t h[80]; + memcpy (h, m_H, 32); + memcpy (h + 32, m_SessionCreatedBuffer + 32, 24); // encrypted payload + SHA256 (h, 56, h); + int paddingLength = m_SessionCreatedBufferLen - 56; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), h, 32); + memcpy (h1.data () + 32, m_SessionCreatedBuffer + 56, paddingLength); + SHA256 (h1.data (), paddingLength + 32, h); + } + // part1 48 bytes + uint8_t s[32]; // public static + CreateEphemeralKey (s); // TODO: take it from RouterContext + m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size + uint8_t nonce[12]; + memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 + i2p::crypto::AEADChaCha20Poly1305 (s, 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_H); + + size_t m3p2Len = 550; // TODO: actual size + uint8_t buf[550]; + memset (buf, 0, m3p2Len - 16); // TODO: fill + uint8_t key[32]; + KeyDerivationFunction3 (m_ExpandedPrivateKey, key); // TODO: take it from RouterContext + memset (nonce, 0, 12); // set nonce to 0 again + i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); + Terminate (); // TODO + } + void NTCP2Session::ClientLogin () { SendSessionRequest (); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b7e83f26..e9a170bd 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,14 +29,19 @@ namespace transport private: + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); + void SendSessionConfirmed (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: @@ -45,9 +50,9 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/; - uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; - size_t m_SessionRequestBufferLen; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32]; + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; + size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; }; class NTCP2Server From 706b976a28c01ba00e147ce5a3dfbe59baa112e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jun 2018 12:52:43 -0400 Subject: [PATCH 084/115] handle and publish NTCP2 address --- libi2pd/RouterContext.cpp | 24 +++++++++++---- libi2pd/RouterContext.h | 6 +++- libi2pd/RouterInfo.cpp | 61 ++++++++++++++++++++++++++++++--------- libi2pd/RouterInfo.h | 7 +++-- 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index b0f1aa51..862352ba 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -2,6 +2,7 @@ #include #include "Config.h" #include "Crypto.h" +#include "Ed25519.h" #include "Timestamp.h" #include "I2NPProtocol.h" #include "NetDb.hpp" @@ -36,7 +37,7 @@ namespace i2p void RouterContext::CreateNewRouter () { m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); - SaveKeys (); + SaveKeys (); NewRouterInfo (); } @@ -49,7 +50,8 @@ namespace i2p port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool nat; i2p::config::GetOption("nat", nat); + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname4; i2p::config::GetOption("ifname4", ifname4); std::string ifname6; i2p::config::GetOption("ifname6", ifname6); @@ -82,6 +84,11 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } + if (ntcp2) + { + NewNTCP2Keys (); + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -102,11 +109,14 @@ namespace i2p void RouterContext::NewNTCP2Keys () { m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); - RAND_bytes (m_NTCP2Keys->staticKey, 32); + RAND_bytes (m_NTCP2Keys->staticPrivateKey, 32); RAND_bytes (m_NTCP2Keys->iv, 16); + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_NTCP2Keys->staticPrivateKey, m_NTCP2Keys->staticPublicKey, ctx); + BN_CTX_free (ctx); // save std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out); - fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); } void RouterContext::SetStatus (RouterStatus status) @@ -455,9 +465,13 @@ namespace i2p m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); } + n2k.close (); } - if (!m_NTCP2Keys) + if (!m_NTCP2Keys) + { NewNTCP2Keys (); + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } } return true; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 02c0156b..ae4aa17e 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -37,7 +37,8 @@ namespace i2p struct NTCP2PrivateKeys { - uint8_t staticKey[32]; + uint8_t staticPublicKey[32]; + uint8_t staticPrivateKey[32]; uint8_t iv[16]; }; @@ -58,6 +59,9 @@ namespace i2p return std::shared_ptr (this, [](i2p::garlic::GarlicDestination *) {}); } + const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; }; + const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; }; + const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; }; uint32_t GetUptime () const; uint32_t GetStartupTime () const { return m_StartupTime; }; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 87f16346..088ba154 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -176,10 +176,14 @@ namespace data auto address = std::make_shared
(); s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->date, sizeof (address->date)); - char transportStyle[5]; - ReadString (transportStyle, 5, s); - if (!strcmp (transportStyle, "NTCP")) + bool isNtcp2 = false; + char transportStyle[6]; + auto transportStyleLen = ReadString (transportStyle, 6, s) - 1; + if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 + { address->transportStyle = eTransportNTCP; + if (transportStyleLen > 4 || transportStyle[4] == '2') isNtcp2= true; + } else if (!strcmp (transportStyle, "SSU")) { address->transportStyle = eTransportSSU; @@ -288,7 +292,7 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports) + if (supportedTransports && !isNtcp2) // we ignore NTCP2 addresses for now. TODO: { addresses->push_back(address); m_SupportedTransports |= supportedTransports; @@ -435,7 +439,7 @@ namespace data s.write ((const char *)&address.date, sizeof (address.date)); std::stringstream properties; if (address.transportStyle == eTransportNTCP) - WriteString ("NTCP", s); + WriteString (address.IsNTCP2 () ? "NTCP2" : "NTCP", s); else if (address.transportStyle == eTransportSSU) { WriteString ("SSU", s); @@ -451,10 +455,13 @@ namespace data else WriteString ("", s); - WriteString ("host", properties); - properties << '='; - WriteString (address.host.to_string (), properties); - properties << ';'; + if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + { + WriteString ("host", properties); + properties << '='; + WriteString (address.host.to_string (), properties); + properties << ';'; + } if (address.transportStyle == eTransportSSU) { // write introducers if any @@ -529,10 +536,23 @@ namespace data properties << ';'; } } - WriteString ("port", properties); - properties << '='; - WriteString (boost::lexical_cast(address.port), properties); - properties << ';'; + + if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + { + WriteString ("port", properties); + properties << '='; + WriteString (boost::lexical_cast(address.port), properties); + properties << ';'; + } + if (address.IsNTCP2 ()) + { + // publish s and v for NTCP2 + WriteString ("s", properties); properties << '='; + WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; + WriteString ("v", properties); properties << '='; + WriteString ("2", properties); properties << ';'; + // TODO: publish "i" + } uint16_t size = htobe16 (properties.str ().size ()); s.write ((char *)&size, sizeof (size)); @@ -668,6 +688,21 @@ namespace data m_Caps |= eSSUIntroducer; } + void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv) + { + for (const auto& it: *m_Addresses) // don't insert one more NTCP2 + if (it->ntcp2) return; + auto addr = std::make_shared
(); + addr->port = 0; + addr->transportStyle = eTransportNTCP; + addr->cost = 14; + addr->date = 0; + addr->ntcp2.reset (new NTCP2Ext ()); + memcpy (addr->ntcp2->staticKey, staticKey, 32); + memcpy (addr->ntcp2->iv, iv, 32); + m_Addresses->push_back(std::move(addr)); + } + bool RouterInfo::AddIntroducer (const Introducer& introducer) { for (auto& addr : *m_Addresses) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 1125bdef..a12b23e3 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -92,8 +92,8 @@ namespace data struct NTCP2Ext { - uint8_t staticKey[32]; - uint8_t iv[16]; + Tag<32> staticKey; + Tag<16> iv; }; struct Address @@ -122,6 +122,8 @@ namespace data { return !(*this == other); } + + bool IsNTCP2 () const { return (bool)ntcp2; }; }; typedef std::list > Addresses; @@ -143,6 +145,7 @@ namespace data void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); + void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv); bool AddIntroducer (const Introducer& introducer); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only From e05110ff444cee2bbd3d61c09c03580bb98e1ca2 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jun 2018 14:56:03 -0400 Subject: [PATCH 085/115] send RouterInfo in SessionConfirmed --- libi2pd/NTCP2.cpp | 20 +++++++++++--------- libi2pd/RouterContext.cpp | 11 ++++++----- libi2pd/RouterInfo.cpp | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 2dd18960..71af855c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -7,6 +7,7 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" +#include "RouterContext.h" #include "NTCP2.h" namespace i2p @@ -153,7 +154,7 @@ namespace transport memset (options, 0, 16); htobe16buf (options, 2); // ver htobe16buf (options + 2, paddingLength); // padLen - htobe16buf (options + 4, 550); // m3p2Len TODO: + htobe16buf (options + 4, i2p::context.GetRouterInfo ().GetBufferLen () + 20); // m3p2Len (RI header + RI + MAC for now) TODO: implement options // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved @@ -255,24 +256,25 @@ namespace transport SHA256 (h1.data (), paddingLength + 32, h); } // part1 48 bytes - uint8_t s[32]; // public static - CreateEphemeralKey (s); // TODO: take it from RouterContext m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 - i2p::crypto::AEADChaCha20Poly1305 (s, 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_H); - size_t m3p2Len = 550; // TODO: actual size - uint8_t buf[550]; - memset (buf, 0, m3p2Len - 16); // TODO: fill + size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; + std::vector buf(m3p2Len - 16); + buf[0] = 2; // block + htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI + buf[3] = 0; // flag + memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); uint8_t key[32]; - KeyDerivationFunction3 (m_ExpandedPrivateKey, key); // TODO: take it from RouterContext + KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 862352ba..9bd6da9f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -84,11 +84,6 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } - if (ntcp2) - { - NewNTCP2Keys (); - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -97,6 +92,12 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); + + if (ntcp2) + { + NewNTCP2Keys (); + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } } void RouterContext::UpdateRouterInfo () diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 088ba154..a0b818fb 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -699,7 +699,7 @@ namespace data addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); memcpy (addr->ntcp2->staticKey, staticKey, 32); - memcpy (addr->ntcp2->iv, iv, 32); + memcpy (addr->ntcp2->iv, iv, 16); m_Addresses->push_back(std::move(addr)); } From d5214099c5f3c43b2282ca4c0d1cf33b67a98660 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 10:53:25 +0300 Subject: [PATCH 086/115] move out android binary build info from README little change in MSYS build script --- README.md | 6 ------ build/build_mingw.cmd | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9b7e42d4..8fc8393a 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,6 @@ Build instructions: * [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/) * [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/) * [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/) -* android executable binary build: - - clone https://github.com/unlnown542a/i2pd.git or download https://github.com/unlnown542a/i2pd/archive/openssl.zip - - change to i2pd/android_binary_only - - edit jni/Application.mk - define path to static libs I2PD_LIBS_PATH - - in the directory i2pd/android_binary_only run: ndk-build -j4 - - find compiled binary - libs/armeabi-v7a/i2pd **Supported systems:** diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index cc6a15fa..e7811b0b 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -16,7 +16,8 @@ REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\m set "WD=C:\msys64\usr\bin\" set MSYS2_PATH_TYPE=inherit set CHERE_INVOKING=enabled_from_arguments -set MSYSTEM=MSYS +REM set MSYSTEM=MSYS +set MSYSTEM=MINGW32 set "xSH=%WD%bash -lc" From e1bfa786fc203806e8fb176340c8f0786e7e5e05 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 11:59:54 +0300 Subject: [PATCH 087/115] fix #1192 --- contrib/apparmor/usr.sbin.i2pd | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/apparmor/usr.sbin.i2pd b/contrib/apparmor/usr.sbin.i2pd index 168070da..afa59563 100644 --- a/contrib/apparmor/usr.sbin.i2pd +++ b/contrib/apparmor/usr.sbin.i2pd @@ -19,6 +19,7 @@ /etc/nsswitch.conf r, /etc/resolv.conf r, /run/resolvconf/resolv.conf r, + /run/systemd/resolve/stub-resolv.conf r, # path specific (feel free to modify if you have another paths) /etc/i2pd/** r, From a59cdcc9e0cc0ff630e12c980e90f1f3fd490ebb Mon Sep 17 00:00:00 2001 From: l-n-s Date: Sat, 16 Jun 2018 08:05:43 -0400 Subject: [PATCH 088/115] Update contrib/i2pd.conf file with more options --- contrib/i2pd.conf | 130 +++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 41 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index c87a2c0b..123df754 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -26,15 +26,11 @@ ## Log messages above this level (debug, *info, warn, error, none) ## If you set it to none, logging will be disabled # loglevel = info - -## Path to storage of i2pd data (RI, keys, peer profiles, ...) -## Default: ~/.i2pd or /var/lib/i2pd -# datadir = /var/lib/i2pd +## Write full CLF-formatted date and time to log (default: write only time) +# logclftime = true ## Daemon mode. Router will go to background after start # daemon = true -## Run as a service. Router will use system folders like ‘/var/lib/i2pd’ -# service = true ## Specify a family, router belongs to (default - none) # family = @@ -55,9 +51,15 @@ ipv6 = false ## Network interface to bind to # ifname = +## You can specify different interfaces for IPv4 and IPv6 +# ifname4 = +# ifname6 = ## Enable NTCP transport (default = true) # ntcp = true +## If you run i2pd behind a proxy server, you can only use NTCP transport with ntcpproxy option +## Should be http://address:port or socks://address:port +# ntcpproxy = http://127.0.0.1:8118 ## Enable SSU transport (default = true) # ssu = true @@ -69,6 +71,8 @@ ipv6 = false ## X - unlimited ## Default is X for floodfill, L for regular node # bandwidth = L +## Max % of bandwidth limit for transit. 0-100. 100 by default +# share = 100 ## Router will not accept transit tunnels, disabling transit traffic completely ## (default = false) @@ -77,46 +81,17 @@ ipv6 = false ## Router will be floodfill # floodfill = true -[limits] -## Maximum active transit sessions (default:2500) -# transittunnels = 2500 - -[precomputation] -## Enable or disable elgamal precomputation table -## By default, enabled on i386 hosts -# elgamal = true - -[upnp] -## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) -# enabled = false - -## Name i2pd appears in UPnP forwardings list (default = I2Pd) -# name = I2Pd - -[reseed] -## Enable or disable reseed data verification. -verify = true -## URLs to request reseed data from, separated by comma -## Default: "mainline" I2P Network reseeds -# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ -## Path to local reseed data file (.su3) for manual reseeding -# file = /path/to/i2pseeds.su3 -## or HTTPS URL to reseed from -# file = https://legit-website.com/i2pseeds.su3 - -[addressbook] -## AddressBook subscription URL for initial setup -## Default: inr.i2p at "mainline" I2P Network -# defaulturl = http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt -## Optional subscriptions URLs, separated by comma -# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt - [http] +## Web Console settings ## Uncomment and set to 'false' to disable Web Console # enabled = true ## Address and port service will listen on address = 127.0.0.1 port = 7070 +## Uncomment following lines to enable Web Console authentication +# auth = true +# user = i2pd +# pass = changeme [httpproxy] ## Uncomment and set to 'false' to disable HTTP Proxy @@ -126,6 +101,11 @@ address = 127.0.0.1 port = 4444 ## Optional keys file for proxy local destination # keys = http-proxy-keys.dat +## Enable address helper for adding .i2p domains with "jump URLs" (default: true) +# addresshelper = true +## Address of a proxy server inside I2P, which is used to visit regular Internet +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. [socksproxy] ## Uncomment and set to 'false' to disable SOCKS Proxy @@ -135,13 +115,13 @@ address = 127.0.0.1 port = 4447 ## Optional keys file for proxy local destination # keys = socks-proxy-keys.dat - ## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Uncomment and set to 'true' to enable using of SOCKS outproxy # outproxy.enabled = false ## Address and port of outproxy # outproxy = 127.0.0.1 # outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. [sam] ## Uncomment and set to 'true' to enable SAM Bridge @@ -170,3 +150,71 @@ enabled = true ## Address and port service will listen on # address = 127.0.0.1 # port = 7650 +## Authentication password. "itoopie" by default +# password = itoopie + +[precomputation] +## Enable or disable elgamal precomputation table +## By default, enabled on i386 hosts +# elgamal = true + +[upnp] +## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) +# enabled = false +## Name i2pd appears in UPnP forwardings list (default = I2Pd) +# name = I2Pd + +[reseed] +## Options for bootstrapping into I2P network, aka reseeding +## Enable or disable reseed data verification. +verify = true +## URLs to request reseed data from, separated by comma +## Default: "mainline" I2P Network reseeds +# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ +## Path to local reseed data file (.su3) for manual reseeding +# file = /path/to/i2pseeds.su3 +## or HTTPS URL to reseed from +# file = https://legit-website.com/i2pseeds.su3 +## Path to local ZIP file or HTTPS URL to reseed from +# zipfile = /path/to/netDb.zip +## If you run i2pd behind a proxy server, set proxy server for reseeding here +## Should be http://address:port or socks://address:port +# proxy = http://127.0.0.1:8118 +## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default +# threshold = 25 + +[addressbook] +## AddressBook subscription URL for initial setup +## Default: inr.i2p at "mainline" I2P Network +# defaulturl = http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt +## Optional subscriptions URLs, separated by comma +# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt + +[limits] +## Maximum active transit sessions (default:2500) +# transittunnels = 2500 +## Limit number of open file descriptors (0 - use system limit) +# openfiles = 0 +## Maximum size of corefile in Kb (0 - use system limit) +# coresize = 0 +## Threshold to start probabalistic backoff with ntcp sessions (0 - use system limit) +# ntcpsoft = 0 +## Maximum number of ntcp sessions (0 - use system limit) +# ntcphard = 0 + +[trust] +## Enable explicit trust options. false by default +# enabled = true +## Make direct I2P connections only to routers in specified Family. +# family = MyFamily +## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities. +# routers = +## Should we hide our router from other routers? false by default +# hidden = true + +[exploratory] +## Exploratory tunnels settings with default values +# inbound.length = 2 +# inbound.quantity = 3 +# outbound.length = 2 +# outbound.quantity = 3 From 6bd73cdea2db75b0f976da308629dc35f3c4ec80 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 18:11:46 +0300 Subject: [PATCH 089/115] Update help message, debian manpage. Prepare changelog message --- debian/changelog | 8 ++++++++ debian/i2pd.1 | 38 +++++++++++++++++++++++++------------- libi2pd/Config.cpp | 7 +++---- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/debian/changelog b/debian/changelog index afddc797..79c368a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +i2pd (2.19.0-1) unstable; urgency=low + + * updated to version 2.19.0/0.9.35 + * update manpage (1) + * fixes in systemd unit (#1089, #1142, #1154, #1155) + + -- R4SAS Tue, 19 Jun 2018 18:00:00 +0000 + i2pd (2.18.0-1) unstable; urgency=low * updated to version 2.18.0/0.9.33 diff --git a/debian/i2pd.1 b/debian/i2pd.1 index e1390891..77e62a6e 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,4 +1,4 @@ -.TH I2PD "1" "March 31, 2015" +.TH I2PD "1" "June 15, 2018" .SH NAME i2pd \- Load-balanced unspoofable packet switching network @@ -40,7 +40,10 @@ Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not se Path to logfile (default - autodetect) .TP \fB\-\-loglevel=\fR -Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR) +Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) +.TP +\fB\-\-logclftime\fR +Log messages with full CLF-formatted date and time .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -51,14 +54,17 @@ The external IP address \fB\-\-port=\fR The port to listen on for incoming connections .TP -\fB\-\-daemon\fR -Router will go to background after start +\fB\-\-ifname=\fR +The network interface to bind to .TP -\fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR +\fB\-\-ifname4=\fR +The network interface to bind to for IPv4 connections +.TP +\fB\-\-ifname6=\fR +The network interface to bind to for IPv6 connections .TP \fB\-\-ipv6\fR -Enable communication through ipv6. false by default +Enable communication through ipv6 (disabled by default) .TP \fB\-\-notransit\fR Router will not accept transit tunnels at startup @@ -67,7 +73,16 @@ Router will not accept transit tunnels at startup Router will be floodfill .TP \fB\-\-bandwidth=\fR -Bandwidth limit: integer in KBps or letter aliases: \fIL (32KBps)\fR, O (256), P (2048), X (>9000) +Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR +.TP +\fB\-\-share=\fR +Limit of transit traffic from max bandwidth in percents. (default: 100) +.TP +\fB\-\-daemon\fR +Router will go to background after start +.TP +\fB\-\-service\fR +Router will use system folders like \fI/var/lib/i2pd\fR .TP \fB\-\-family=\fR Name of a family, router belongs to. @@ -90,16 +105,13 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.RE -.PP -/usr/share/doc/i2pd/examples/hosts.txt.gz -.RS 4 -default I2P hosts file .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). .PP Updated by hagen in 2016. .PP +Updated by R4SAS in 2018. +.PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation .BR On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index a7bc305c..5f108fbb 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -37,8 +37,8 @@ namespace config { ("pidfile", value()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") - ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") - ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") + ("logclftime", value()->zero_tokens()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") @@ -63,7 +63,7 @@ namespace config { #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") - ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something + ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; @@ -331,4 +331,3 @@ namespace config { } // namespace config } // namespace i2p - From bdc7acffbeac0c85aea288936eadc9b4d6e9a514 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 22:38:59 +0300 Subject: [PATCH 090/115] remove zero_tokens(), update manpage --- debian/i2pd.1 | 33 +++++++++++++++++++++++++-------- libi2pd/Config.cpp | 32 ++++++++++++++++---------------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 77e62a6e..6cd63b36 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,4 +1,4 @@ -.TH I2PD "1" "June 15, 2018" +.TH I2PD "1" "June 16, 2018" .SH NAME i2pd \- Load-balanced unspoofable packet switching network @@ -36,14 +36,14 @@ Where to write pidfile (don\'t write by default) \fB\-\-log=\fR Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility) .TP -\fB\-\-logfile\fR +\fB\-\-logfile=\fR Path to logfile (default - autodetect) .TP \fB\-\-loglevel=\fR Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) .TP \fB\-\-logclftime\fR -Log messages with full CLF-formatted date and time +Log messages with full CLF-formatted date and time (\fIfalse\fR by default) .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -63,14 +63,26 @@ The network interface to bind to for IPv4 connections \fB\-\-ifname6=\fR The network interface to bind to for IPv6 connections .TP +\fB\-\-ipv4\fR +Enable communication through ipv6 (\fItrue\fR by default) +.TP \fB\-\-ipv6\fR -Enable communication through ipv6 (disabled by default) +Enable communication through ipv6 (\fIfalse\fR by default) +.TP +\fB\-\-ntcp\fR +Enable usage of NTCP transport (\fItrue\fR by default) +.TP +\fB\-\-ntcpproxy\fR +Set proxy URL for NTCP transport +.TP +\fB\-\-ssu\fR +Enable usage of SSU transport (\fItrue\fR by default) .TP \fB\-\-notransit\fR -Router will not accept transit tunnels at startup +Router will not accept transit tunnels at startup (\fIfalse\fR by default) .TP \fB\-\-floodfill\fR -Router will be floodfill +Router will be floodfill (\fIfalse\fR by default) .TP \fB\-\-bandwidth=\fR Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR @@ -79,10 +91,10 @@ Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256) Limit of transit traffic from max bandwidth in percents. (default: 100) .TP \fB\-\-daemon\fR -Router will go to background after start +Router will go to background after start (\fIfalse\fR by default) .TP \fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR +Router will use system folders like \fI/var/lib/i2pd\fR (\fIfalse\fR by default) .TP \fB\-\-family=\fR Name of a family, router belongs to. @@ -105,6 +117,11 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) +.Sh SEE ALSO +Documentation at +.Pa https://i2pd.readthedocs.io/en/latest/ . +.Pp + .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). .PP diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 5f108fbb..8492601b 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -38,7 +38,7 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") - ("logclftime", value()->zero_tokens()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") @@ -48,21 +48,21 @@ namespace config { ("nat", value()->default_value(true), "Should we assume we are behind NAT?") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->default_value(true), "Enable communication through ipv4") - ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") + ("ipv6", value()->default_value(false), "Enable communication through ipv6") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") - ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") - ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") - ("notransit", value()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") - ("floodfill", value()->zero_tokens()->default_value(false), "Router will be floodfill") + ("daemon", value()->default_value(false), "Router will go to background after start") + ("service", value()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") + ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") + ("floodfill", value()->default_value(false), "Router will be floodfill") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", value()->zero_tokens()->default_value(false), "Enable NTCP2 (experimental)") + ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") - ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") + ("insomnia", value()->default_value(false), "Prevent system from sleeping") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; @@ -79,14 +79,14 @@ namespace config { options_description httpserver("HTTP Server options"); httpserver.add_options() - ("http.enabled", value()->default_value(true), "Enable or disable webconsole") - ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") - ("http.port", value()->default_value(7070), "Webconsole listen port") - ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") - ("http.user", value()->default_value("i2pd"), "Username for basic auth") - ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") - ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") - ("http.hostname", value()->default_value("localhost"),"Expected hostname for WebUI") + ("http.enabled", value()->default_value(true), "Enable or disable webconsole") + ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") + ("http.port", value()->default_value(7070), "Webconsole listen port") + ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") + ("http.user", value()->default_value("i2pd"), "Username for basic auth") + ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") + ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") + ("http.hostname", value()->default_value("localhost"), "Expected hostname for WebUI") ; options_description httpproxy("HTTP Proxy options"); From a027a42c462e51b909ad43d6d90d0e967b636924 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 22:57:18 +0300 Subject: [PATCH 091/115] fix links to online documentation in manpage --- debian/i2pd.1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 6cd63b36..3e0a90ff 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -117,10 +117,13 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.Sh SEE ALSO +.SH SEE ALSO +.PP Documentation at -.Pa https://i2pd.readthedocs.io/en/latest/ . -.Pp +.UR https://i2pd.readthedocs.io/en/latest/ +Read the Docs +.UE . +.PP .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). From 985b618932005404baa485d5a8e6b3ff793f789f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 23:06:01 +0300 Subject: [PATCH 092/115] addng forgotten bracket --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 8492601b..2e6d40bb 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -55,7 +55,7 @@ namespace config { ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") ("floodfill", value()->default_value(false), "Router will be floodfill") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") - ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") + ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") From 58c92b8405f5da687734c1b0d6f7ec63dbb2d3b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Jun 2018 12:56:47 -0400 Subject: [PATCH 093/115] aead/chacha20/poly1305 from openssl 1.1 --- libi2pd/Crypto.cpp | 40 ++++++++++++++++++++++++++++++++++++---- libi2pd/Crypto.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index bdcf5acd..f8fb9946 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,9 +8,13 @@ #include #include "TunnelBase.h" #include -#include "I2PEndian.h" +#if LEGACY_OPENSSL #include "ChaCha20.h" #include "Poly1305.h" +#else +#include +#endif +#include "I2PEndian.h" #include "Log.h" #include "Crypto.h" @@ -1064,7 +1068,10 @@ namespace crypto bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (encrypt && msgLen + 16 < len) return 0; + if (len < msgLen) return false; + if (encrypt && len < msgLen + 16) return false; + bool ret = true; +#if LEGACY_OPENSSL // generate one time poly key uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); @@ -1106,9 +1113,34 @@ namespace crypto uint32_t tag[8]; // calculate Poly1305 tag Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); - if (memcmp (tag, msg + msgLen, 16)) return false; // compare with provided + if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided } - return true; +#else + int outlen = 0; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); + if (encrypt) + { + EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen); + EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen); + EVP_EncryptFinal_ex(ctx, buf, &outlen); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen); + } + else + { + EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen)); + EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_DecryptUpdate(ctx, NULL, &outlen, ad, adLen); + ret = EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen) > 0; + } + + EVP_CIPHER_CTX_free (ctx); +#endif + return ret; } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index af4ec1f8..25646dbb 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -265,7 +265,8 @@ namespace crypto // take care about openssl version #include -#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL +#define LEGACY_OPENSSL ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +#if LEGACY_OPENSSL // define getters and setters introduced in 1.1.0 inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { From 3cec9232940761ebbab170a668f6fc4e26c9bb08 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 19 Jun 2018 15:08:16 +0300 Subject: [PATCH 094/115] Update tunnels.conf --- contrib/tunnels.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/tunnels.conf b/contrib/tunnels.conf index be8681dc..cd6cc910 100644 --- a/contrib/tunnels.conf +++ b/contrib/tunnels.conf @@ -31,3 +31,4 @@ keys = irc-keys.dat #keys = pop3-keys.dat # see more examples in /usr/share/doc/i2pd/configuration.md.gz +# or at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ From 4d9143734fe3aff50dc63c8365450a115c57f5eb Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 19 Jun 2018 15:11:48 +0300 Subject: [PATCH 095/115] store standart configs as docs in deb packages --- debian/docs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/docs b/debian/docs index b43bf86b..b67deb18 100644 --- a/debian/docs +++ b/debian/docs @@ -1 +1,4 @@ README.md +contrib/i2pd.conf +contrib/subscriptions.txt +contrib/tunnels.conf From 9c7cadb191584a064150b1002cb734fed909bf4d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jun 2018 11:14:22 -0400 Subject: [PATCH 096/115] better implementation of x25519 --- libi2pd/Ed25519.cpp | 65 +++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 05721d80..17264926 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -419,13 +419,8 @@ namespace crypto auto z2 = BN_CTX_get (ctx); BN_zero (z2); auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); auto z3 = BN_CTX_get (ctx); BN_one (z3); - auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); - auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); - auto b = BN_CTX_get (ctx); auto bb = BN_CTX_get (ctx); - auto e = BN_CTX_get (ctx); auto c = BN_CTX_get (ctx); - auto d = BN_CTX_get (ctx); - auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); - auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); + auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666); + auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); unsigned int swap = 0; auto bits = BN_num_bits (k); while(bits) @@ -439,49 +434,33 @@ namespace crypto std::swap (z2, z3); } swap = k_t; - // a = x2 + z2 - BN_mod_add(a, x2, z2, q, ctx); - // aa = a^2 - BN_mod_sqr(aa, a, q, ctx); - // b = x2 - z2 - BN_mod_sub(b, x2, z2, q, ctx); - // bb = b^2 - BN_mod_sqr(bb, b, q, ctx); - // e = aa - bb - BN_mod_sub(e, aa, bb, q, ctx); - // c = x3 + z3 - BN_mod_add(c, x3, z3, q, ctx); - // d = x3 - z3 - BN_mod_sub(d, x3, z3, q, ctx); - // da = d * a - BN_mod_mul(da, d, a, q, ctx); - // cb = c * b - BN_mod_mul(cb, c, b, q, ctx); - // x3 = ( da + cb )^2 - BN_mod_add(tmp1, da, cb, q, ctx); - BN_mod_sqr(x3, tmp1, q, ctx); - // z3 == x1 * (da - cb)^2 - BN_mod_sub(tmp1, da, cb, q, ctx); - BN_mod_sqr(tmp2, tmp1, q, ctx); - BN_mod_mul(z3, x1, tmp2, q, ctx); - // x2 = aa * bb - BN_mod_mul(x2, aa, bb, q, ctx); - // z2 = e * (aa + a24 * e) - BN_mod_mul(tmp1, a24, e, q, ctx); - BN_mod_add(tmp2, aa, tmp1, q, ctx); - BN_mod_mul(z2, e, tmp2, q, ctx); + BN_mod_sub(tmp0, x3, z3, q, ctx); + BN_mod_sub(tmp1, x2, z2, q, ctx); + BN_mod_add(x2, x2, z2, q, ctx); + BN_mod_add(z2, x3, z3, q, ctx); + BN_mod_mul(z3, tmp0, x2, q, ctx); + BN_mod_mul(z2, z2, tmp1, q, ctx); + BN_mod_sqr(tmp0, tmp1, q, ctx); + BN_mod_sqr(tmp1, x2, q, ctx); + BN_mod_add(x3, z3, z2, q, ctx); + BN_mod_sub(z2, z3, z2, q, ctx); + BN_mod_mul(x2, tmp1, tmp0, q, ctx); + BN_mod_sub(tmp1, tmp1, tmp0, q, ctx); + BN_mod_sqr(z2, z2, q, ctx); + BN_mod_mul(z3, tmp1, c121666, q, ctx); + BN_mod_sqr(x3, x3, q, ctx); + BN_mod_add(tmp0, tmp0, z3, q, ctx); + BN_mod_mul(z3, x1, z2, q, ctx); + BN_mod_mul(z2, tmp1, tmp0, q, ctx); } if (swap) { std::swap (x2, x3); std::swap (z2, z3); } - // x2 * (z2 ^ (q - 2)) - BN_set_word(tmp1, 2); - BN_sub(tmp2, q, tmp1); - BN_mod_exp(tmp1, z2, tmp2, q, ctx); + BN_mod_inverse (z2, z2, q, ctx); BIGNUM * res = BN_new (); // not from ctx - BN_mod_mul(res, x2, tmp1, q, ctx); + BN_mod_mul(res, x2, z2, q, ctx); BN_CTX_end (ctx); return res; } From b5682012d3657deecd5047f3569c26d18587707d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jun 2018 15:43:47 -0400 Subject: [PATCH 097/115] process SessionRequest and send SessionCreated for NTCP2 --- libi2pd/Crypto.cpp | 2 +- libi2pd/NTCP2.cpp | 123 +++++++++++++++++++++++++++++++++++++++++---- libi2pd/NTCP2.h | 13 +++-- 3 files changed, 123 insertions(+), 15 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index f8fb9946..7e320888 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,6 +8,7 @@ #include #include "TunnelBase.h" #include +#include "Crypto.h" #if LEGACY_OPENSSL #include "ChaCha20.h" #include "Poly1305.h" @@ -16,7 +17,6 @@ #endif #include "I2PEndian.h" #include "Log.h" -#include "Crypto.h" namespace i2p { diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 71af855c..187f4435 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -66,7 +66,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64]; @@ -81,12 +81,12 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); MixKey (inputKeyMaterial, derived); } - void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) { uint8_t h[64]; memcpy (h, m_H, 32); @@ -106,7 +106,7 @@ namespace transport // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, ctx); BN_CTX_free (ctx); MixKey (inputKeyMaterial, derived); } @@ -122,11 +122,9 @@ namespace transport void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { - uint8_t key[32]; - RAND_bytes (key, 32); - i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); + RAND_bytes (m_EphemeralPrivateKey, 32); BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_ExpandedPrivateKey, pub, ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, ctx); BN_CTX_free (ctx); } @@ -148,7 +146,7 @@ namespace transport encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key); + KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -184,6 +182,96 @@ namespace transport } } + void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ()); + Terminate (); + } + else + { + // decrypt X + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (i2p::context.GetIdentHash ()); + decryption.SetIV (i2p::context.GetNTCP2IV ()); + decryption.Decrypt (m_SessionRequestBuffer, 32, m_Y); + decryption.GetIV (m_IV); // save IV for SessionCreated + // decryption key for next block + uint8_t key[32]; + KeyDerivationFunction1 (m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Y, key); + // 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, key, nonce, options, 16, false)) // decrypt + { + uint16_t version = bufbe16toh (options); + if (version == 2) + { + uint16_t paddingLen = bufbe16toh (options + 2); + m_SessionRequestBufferLen = paddingLen + 64; + // TODO: check tsA + if (paddingLen > 0) + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + else + SendSessionCreated (); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", version); + Terminate (); + } + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed "); + Terminate (); + } + } + } + + void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding read error: ", ecode.message ()); + Terminate (); + } + else + SendSessionCreated (); + } + + void NTCP2Session::SendSessionCreated () + { + m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + // generate key pair (y) + uint8_t y[32]; + CreateEphemeralKey (y); + // encrypt Y + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (i2p::context.GetIdentHash ()); + encryption.SetIV (m_IV); + encryption.Encrypt (y, 32, m_SessionCreatedBuffer); + // encryption key for next block (m_K) + KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + auto paddingLen = rand () % (287 - 56); + uint8_t options[8]; + memset (options, 0, 8); + htobe16buf (options, paddingLen); // padLen + htobe32buf (options + 4, i2p::util::GetSecondsSinceEpoch ()); // tsB + // 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, 8, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 24, true); // encrypt + // fill padding + RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 56), boost::asio::transfer_all (), + 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) { if (ecode) @@ -201,7 +289,7 @@ namespace transport decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); // decryption key for next block (m_K) - KeyDerivationFunction2 (m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC uint8_t payload[8]; uint8_t nonce[12]; @@ -240,6 +328,7 @@ namespace transport } } + void NTCP2Session::SendSessionConfirmed () { // update AD @@ -287,11 +376,25 @@ namespace transport Terminate (); // TODO } + void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); + Terminate (); // TODO + } + void NTCP2Session::ClientLogin () { SendSessionRequest (); } + void NTCP2Session::ServerLogin () + { + m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer, 64), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e9a170bd..1bfcd0c2 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -25,20 +25,25 @@ namespace transport boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ClientLogin (); // Alice + void ServerLogin (); // Bob void SendI2NPMessages (const std::vector >& msgs) {}; // TODO private: void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); + void SendSessionCreated (); void SendSessionConfirmed (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -49,8 +54,8 @@ namespace transport boost::asio::ip::tcp::socket m_Socket; bool m_IsEstablished, m_IsTerminated; - uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32]; + uint8_t m_EphemeralPrivateKey[32]; // x25519 + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; }; From 3cec5235c9db310d4b6f729a154cc27c1da10665 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Jun 2018 16:09:22 -0400 Subject: [PATCH 098/115] NTCP2 according to new specs --- libi2pd/NTCP2.cpp | 71 ++++++++++++++++++++++++++++++----------------- libi2pd/NTCP2.h | 1 + 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 187f4435..462c3ad1 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -68,10 +68,17 @@ namespace transport void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { - static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes - uint8_t h[64]; - memcpy (m_CK, protocolName, 32); - SHA256 ((const uint8_t *)protocolName, 32, h); + 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 uint8_t h[64] = + { + 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); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); SHA256 (h, 64, h); @@ -120,6 +127,18 @@ namespace transport MixKey (inputKeyMaterial, derived); } + void NTCP2Session::KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived) + { + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // zerolen + static uint8_t one[1] = { 1 }; + uint8_t k_ab[33], k_ba[32]; + HMAC(EVP_sha256(), tempKey, 32, one, 1, k_ab, &len); + k_ab[32] = 2; + HMAC(EVP_sha256(), k_ab, 33, one, 1, k_ba, &len); + memcpy (derived, isAlice ? k_ab : k_ba, 32); + } + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { RAND_bytes (m_EphemeralPrivateKey, 32); @@ -150,7 +169,7 @@ namespace transport // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); - htobe16buf (options, 2); // ver + options[1] = 2; // ver htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 4, i2p::context.GetRouterInfo ().GetBufferLen () + 20); // m3p2Len (RI header + RI + MAC for now) TODO: implement options // 2 bytes reserved @@ -176,8 +195,8 @@ namespace transport else { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size - // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 56), boost::asio::transfer_all (), + // we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -206,8 +225,7 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, key, nonce, options, 16, false)) // decrypt { - uint16_t version = bufbe16toh (options); - if (version == 2) + if (options[1] == 2) { uint16_t paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; @@ -220,7 +238,7 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", version); + LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); Terminate (); } } @@ -256,19 +274,19 @@ namespace transport encryption.Encrypt (y, 32, m_SessionCreatedBuffer); // encryption key for next block (m_K) KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); - auto paddingLen = rand () % (287 - 56); - uint8_t options[8]; - memset (options, 0, 8); - htobe16buf (options, paddingLen); // padLen - htobe32buf (options + 4, i2p::util::GetSecondsSinceEpoch ()); // tsB + auto paddingLen = rand () % (287 - 64); + 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 uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 8, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 24, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 56), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -282,7 +300,7 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - m_SessionCreatedBufferLen = 56; + m_SessionCreatedBufferLen = 64; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); @@ -291,16 +309,17 @@ namespace transport // decryption key for next block (m_K) KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC - uint8_t payload[8]; + uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, m_K, nonce, payload, 8, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt { - uint16_t paddingLen = bufbe16toh(payload); + uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); + // TODO: check tsB if (paddingLen > 0) { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 56, paddingLen), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else @@ -334,14 +353,14 @@ namespace transport // update AD uint8_t h[80]; memcpy (h, m_H, 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 24); // encrypted payload - SHA256 (h, 56, h); - int paddingLength = m_SessionCreatedBufferLen - 56; + memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { std::vector h1(paddingLength + 32); memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, m_SessionCreatedBuffer + 56, paddingLength); + memcpy (h1.data () + 32, m_SessionCreatedBuffer + 64, paddingLength); SHA256 (h1.data (), paddingLength + 32, h); } // part1 48 bytes diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1bfcd0c2..076a12d4 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -34,6 +34,7 @@ namespace transport void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 + void KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); From dd392941d0734d421d6a27bcf12c9582b5dc6b8d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 20 Jun 2018 05:07:24 +0300 Subject: [PATCH 099/115] update Config.cpp, links to examples, manpage --- contrib/tunnels.conf | 3 +- debian/changelog | 5 ++-- debian/control | 2 +- debian/i2pd.1 | 70 +++++++++++++++++++------------------------- libi2pd/Config.cpp | 24 +++++++-------- 5 files changed, 47 insertions(+), 57 deletions(-) diff --git a/contrib/tunnels.conf b/contrib/tunnels.conf index cd6cc910..3358ffc4 100644 --- a/contrib/tunnels.conf +++ b/contrib/tunnels.conf @@ -30,5 +30,4 @@ keys = irc-keys.dat #destinationport = 110 #keys = pop3-keys.dat -# see more examples in /usr/share/doc/i2pd/configuration.md.gz -# or at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/debian/changelog b/debian/changelog index 79c368a6..1b87e73c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,11 @@ -i2pd (2.19.0-1) unstable; urgency=low +i2pd (2.19.0-pre1) unstable; urgency=low * updated to version 2.19.0/0.9.35 * update manpage (1) + * update docfiles * fixes in systemd unit (#1089, #1142, #1154, #1155) - -- R4SAS Tue, 19 Jun 2018 18:00:00 +0000 + -- R4SAS Wed, 20 Jun 2018 02:11:00 +0000 i2pd (2.18.0-1) unstable; urgency=low diff --git a/debian/control b/debian/control index 7bd18ebb..76d753d4 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Architecture: any Pre-Depends: adduser Depends: ${shlibs:Depends}, ${misc:Depends} Suggests: tor, privoxy, apparmor -Description: A full-featured C++ implementation of I2P client. +Description: Full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants don't reveal their real IP addresses. diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 3e0a90ff..72b2c261 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,22 +1,19 @@ -.TH I2PD "1" "June 16, 2018" +.TH "I2PD" "1" "June 20, 2018" -.SH NAME -i2pd \- Load-balanced unspoofable packet switching network - -.SH SYNOPSIS +.SH "NAME" +i2pd \- Full-featured C++ implementation of I2P client. +.SH "SYNOPSIS" .B i2pd [\fIOPTION1\fR] [\fIOPTION2\fR]... - -.SH DESCRIPTION +.SH "DESCRIPTION" i2pd is a C++ implementation of the router for the I2P anonymizing network, offering a simple layer that identity-sensitive applications can use to securely communicate. All data is wrapped with several layers of encryption, and the network is both distributed and dynamic, with no trusted parties. - .PP Any of the configuration options below can be used in the \fBDAEMON_ARGS\fR variable in \fI/etc/default/i2pd\fR. -.BR +.SH "OPTIONS" .TP \fB\-\-help\fR Show available options. @@ -43,7 +40,7 @@ Path to logfile (default - autodetect) Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) .TP \fB\-\-logclftime\fR -Log messages with full CLF-formatted date and time (\fIfalse\fR by default) +Log messages with full CLF-formatted date and time (\fIdisabled\fR by default) .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -64,25 +61,25 @@ The network interface to bind to for IPv4 connections The network interface to bind to for IPv6 connections .TP \fB\-\-ipv4\fR -Enable communication through ipv6 (\fItrue\fR by default) +Enable communication through ipv6 (\fIenabled\fR by default) .TP \fB\-\-ipv6\fR -Enable communication through ipv6 (\fIfalse\fR by default) +Enable communication through ipv6 (\fIdisabled\fR by default) .TP \fB\-\-ntcp\fR -Enable usage of NTCP transport (\fItrue\fR by default) +Enable usage of NTCP transport (\fIenabled\fR by default) .TP -\fB\-\-ntcpproxy\fR +\fB\-\-ntcpproxy=\fR Set proxy URL for NTCP transport .TP \fB\-\-ssu\fR -Enable usage of SSU transport (\fItrue\fR by default) +Enable usage of SSU transport (\fIenabled\fR by default) .TP \fB\-\-notransit\fR -Router will not accept transit tunnels at startup (\fIfalse\fR by default) +Router will not accept transit tunnels at startup (\fIdisabled\fR by default) .TP \fB\-\-floodfill\fR -Router will be floodfill (\fIfalse\fR by default) +Router will be floodfill (\fIdisabled\fR by default) .TP \fB\-\-bandwidth=\fR Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR @@ -91,22 +88,21 @@ Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256) Limit of transit traffic from max bandwidth in percents. (default: 100) .TP \fB\-\-daemon\fR -Router will go to background after start (\fIfalse\fR by default) +Router will go to background after start (\fIdisabled\fR by default) .TP \fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR (\fIfalse\fR by default) +Router will use system folders like \fI/var/lib/i2pd\fR (\fIdisabled\fR by default) .TP \fB\-\-family=\fR Name of a family, router belongs to. .PP -See service-specific parameters in example config file \fIcontrib/i2pd.conf\fR - -.SH FILES -.PP +Switchs, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file. +.RE +See service-specific parameters in example config file \fI/usr/share/doc/i2pd/i2pd.conf.gz\fR +.SH "FILES" /etc/i2pd/i2pd.conf, /etc/i2pd/tunnels.conf, /etc/default/i2pd .RS 4 i2pd configuration files (when running as a system service) - .RE .PP /var/lib/i2pd/ @@ -117,21 +113,15 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.SH SEE ALSO +.SH "SEE ALSO" +Documentation at Read the Docs: \m[blue]\fBhttps://i2pd\&.readthedocs\&.io/en/latest/\fR\m[] +.SH "AUTHOR" +This manual page was written by kytv <\m[blue]\fBkillyourtv@i2pmail\&.org\fR\m[]> for the Debian system (but may be used by others). +.RE +Updated by hagen <\m[blue]\fBhagen@i2pmail\&.org\fR\m[]> in 2016. +.RE +Updated by R4SAS <\m[blue]\fBr4sas@i2pmail\&.org\fR\m[]> in 2018. .PP -Documentation at -.UR https://i2pd.readthedocs.io/en/latest/ -Read the Docs -.UE . -.PP - -.SH AUTHOR -This manual page was written by kytv for the Debian system (but may be used by others). -.PP -Updated by hagen in 2016. -.PP -Updated by R4SAS in 2018. -.PP -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation -.BR +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation. +.RE On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 2e6d40bb..251e91df 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -38,31 +38,31 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") - ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", value()->default_value(true), "Should we assume we are behind NAT?") + ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", value()->default_value(true), "Enable communication through ipv4") - ("ipv6", value()->default_value(false), "Enable communication through ipv6") + ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") - ("daemon", value()->default_value(false), "Router will go to background after start") - ("service", value()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") - ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") - ("floodfill", value()->default_value(false), "Router will be floodfill") + ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") + ("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") + ("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)") + ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", value()->default_value(true), "Enable NTCP transport") - ("ssu", value()->default_value(true), "Enable SSU transport") + ("ntcp", bool_switch()->default_value(true), "Enable NTCP transport (default: enabled)") + ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental)") + ("ntcp2", bool_switch()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") - ("insomnia", value()->default_value(false), "Prevent system from sleeping") + ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; From 7d862d8eba11364e957d2a9efc2614acef84fd05 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 20 Jun 2018 14:48:29 +0300 Subject: [PATCH 100/115] service and daemon works as bool without values, other requires true/false --- debian/i2pd.1 | 6 +++--- libi2pd/Config.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 72b2c261..91e3b60f 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -60,19 +60,19 @@ The network interface to bind to for IPv4 connections \fB\-\-ifname6=\fR The network interface to bind to for IPv6 connections .TP -\fB\-\-ipv4\fR +\fB\-\-ipv4=\fR Enable communication through ipv6 (\fIenabled\fR by default) .TP \fB\-\-ipv6\fR Enable communication through ipv6 (\fIdisabled\fR by default) .TP -\fB\-\-ntcp\fR +\fB\-\-ntcp=\fR Enable usage of NTCP transport (\fIenabled\fR by default) .TP \fB\-\-ntcpproxy=\fR Set proxy URL for NTCP transport .TP -\fB\-\-ssu\fR +\fB\-\-ssu=\fR Enable usage of SSU transport (\fIenabled\fR by default) .TP \fB\-\-notransit\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 251e91df..1ff55dd6 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -45,9 +45,9 @@ namespace config { ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") + ("nat", value()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv4", value()->default_value(true), "Enable communication through ipv4 (default: enabled)") ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") @@ -56,10 +56,10 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", bool_switch()->default_value(true), "Enable NTCP transport (default: enabled)") - ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") + ("ntcp", value()->default_value(true), "Enable NTCP transport (default: enabled)") + ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", bool_switch()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") From 96411cc93eda6582b795e91e4ddf67c82646ae39 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 21 Jun 2018 12:39:24 -0400 Subject: [PATCH 101/115] derive keys for siphash --- libi2pd/NTCP2.cpp | 26 +++++++++++++++++++------- libi2pd/NTCP2.h | 4 +++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 462c3ad1..a925e62f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -7,6 +7,7 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" +#include "Siphash.h" #include "RouterContext.h" #include "NTCP2.h" @@ -127,16 +128,26 @@ namespace transport MixKey (inputKeyMaterial, derived); } - void NTCP2Session::KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived) + void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // zerolen + HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; - uint8_t k_ab[33], k_ba[32]; - HMAC(EVP_sha256(), tempKey, 32, one, 1, k_ab, &len); - k_ab[32] = 2; - HMAC(EVP_sha256(), k_ab, 33, one, 1, k_ba, &len); - memcpy (derived, isAlice ? k_ab : k_ba, 32); + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Kab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)). + + static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32]; + HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) + uint8_t h[39]; + memcpy (h, m_H, 32); + memcpy (h + 32, "siphash", 7); + HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash") + HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01)) + HMAC(EVP_sha256(), master, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(sip_master, zerolen) + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Siphashab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Siphashab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Siphashab, 33, m_Siphashba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -392,6 +403,7 @@ namespace transport void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); + KeyDerivationFunctionDataPhase (); Terminate (); // TODO } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 076a12d4..57556674 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -34,7 +34,7 @@ namespace transport void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 - void KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived); + void KeyDerivationFunctionDataPhase (); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -59,6 +59,8 @@ namespace transport uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; + // data phase + uint8_t m_Kab[33], m_Kba[32], m_Siphashab[33], m_Siphashba[32]; }; class NTCP2Server From 5b295921743cb6f51c6618f825850c9ac93707e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 21 Jun 2018 16:24:19 -0400 Subject: [PATCH 102/115] generate sipkeys for data pahse of NTCP2 --- libi2pd/NTCP2.cpp | 62 +++++++++++++++++++++++++++++++++++++++++------ libi2pd/NTCP2.h | 12 ++++++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a925e62f..db509186 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -19,7 +19,8 @@ namespace transport TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), + m_NextReceivedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -36,6 +37,7 @@ namespace transport delete[] m_SessionRequestBuffer; delete[] m_SessionCreatedBuffer; delete[] m_SessionConfirmedBuffer; + delete[] m_NextReceivedBuffer; } void NTCP2Session::Terminate () @@ -130,13 +132,13 @@ namespace transport void NTCP2Session::KeyDerivationFunctionDataPhase () { + char buf[100]; uint8_t tempKey[32]; unsigned int len; HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)). m_Kab[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)). - + HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)) static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32]; HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) uint8_t h[39]; @@ -145,9 +147,9 @@ namespace transport HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash") HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01)) HMAC(EVP_sha256(), master, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(sip_master, zerolen) - HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Siphashab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). - m_Siphashab[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_Siphashab, 33, m_Siphashba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Sipkeysab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Sipkeysab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Sipkeysab, 33, m_Sipkeysba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -394,6 +396,11 @@ namespace transport KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); memset (nonce, 0, 12); // set nonce to 0 again i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + uint8_t tmp[48]; + memcpy (tmp, m_SessionConfirmedBuffer, 48); + memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext); + memcpy (m_SessionConfirmedBuffer, tmp, 48); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), @@ -404,7 +411,8 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - Terminate (); // TODO + memcpy (m_IV, m_Sipkeysba + 16, 8); //Alice + ReceiveLength (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -426,6 +434,46 @@ namespace transport std::placeholders::_1, std::placeholders::_2)); } + void NTCP2Session::ReceiveLength () + { + boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); + Terminate (); + } + else + { + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Kba); // assume Alice TODO: + m_NextReceivedLen = be16toh (m_NextReceivedLen ^ buf16toh(m_ReceiveIV)); + LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + Receive (); + } + } + + void NTCP2Session::Receive () + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); + Terminate (); + } + Terminate (); // TODO + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 57556674..5f8d116d 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -36,6 +36,7 @@ namespace transport void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void KeyDerivationFunctionDataPhase (); + // establish void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void SendSessionCreated (); @@ -49,6 +50,12 @@ namespace transport void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + // data + void ReceiveLength (); + void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void Receive (); + void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: NTCP2Server& m_Server; @@ -60,7 +67,10 @@ namespace transport uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase - uint8_t m_Kab[33], m_Kba[32], m_Siphashab[33], m_Siphashba[32]; + uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; + uint16_t m_NextReceivedLen; + uint8_t * m_NextReceivedBuffer; + uint8_t m_ReceiveIV[8]; }; class NTCP2Server From 5884852612d2f091c8793912fa1641c8bc69b24b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jun 2018 12:20:35 -0400 Subject: [PATCH 103/115] correct usage of sipkeys --- libi2pd/NTCP2.cpp | 7 +++---- libi2pd/Siphash.h | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index db509186..f7e5e796 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -132,7 +132,6 @@ namespace transport void NTCP2Session::KeyDerivationFunctionDataPhase () { - char buf[100]; uint8_t tempKey[32]; unsigned int len; HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; @@ -411,7 +410,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - memcpy (m_IV, m_Sipkeysba + 16, 8); //Alice + memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice ReceiveLength (); } @@ -449,8 +448,8 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Kba); // assume Alice TODO: - m_NextReceivedLen = be16toh (m_NextReceivedLen ^ buf16toh(m_ReceiveIV)); + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Sipkeysba); // assume Alice TODO: + m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h index 3e74c6e9..aa8b8631 100644 --- a/libi2pd/Siphash.h +++ b/libi2pd/Siphash.h @@ -19,14 +19,14 @@ namespace crypto constexpr int crounds = 2; constexpr int drounds = 4; - uint64_t rotl(const uint64_t & x, int b) + inline uint64_t rotl(const uint64_t & x, int b) { uint64_t ret = x << b; ret |= x >> (64 - b); return ret; } - void u32to8le(const uint32_t & v, uint8_t * p) + inline void u32to8le(const uint32_t & v, uint8_t * p) { p[0] = (uint8_t) v; p[1] = (uint8_t) (v >> 8); @@ -34,7 +34,7 @@ namespace crypto p[3] = (uint8_t) (v >> 24); } - void u64to8le(const uint64_t & v, uint8_t * p) + inline void u64to8le(const uint64_t & v, uint8_t * p) { p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; @@ -46,7 +46,7 @@ namespace crypto p[7] = (v >> 56) & 0xff; } - uint64_t u8to64le(const uint8_t * p) + inline uint64_t u8to64le(const uint8_t * p) { uint64_t i = 0; int idx = 0; @@ -58,7 +58,7 @@ namespace crypto return i; } - void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) + inline void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) { _v0 += _v1; _v1 = rotl(_v1, 13); @@ -79,7 +79,7 @@ namespace crypto /** hashsz must be 8 or 16 */ template - void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) + inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) { uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v1 = 0x646f72616e646f6dULL; @@ -149,4 +149,4 @@ namespace crypto } } -#endif \ No newline at end of file +#endif From 0aa618b938bd76f0fac8f5ca07b594649a23f6c8 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jun 2018 15:02:49 -0400 Subject: [PATCH 104/115] process AEAD/Chacha20/Poly1305 frame for data phase of NTCP2 --- libi2pd/Crypto.cpp | 22 +++++++++++++--------- libi2pd/NTCP2.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- libi2pd/NTCP2.h | 2 ++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 7e320888..6d859342 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,19 +1081,23 @@ namespace crypto chacha20 (buf, msgLen, nonce, key, 1); // create Poly1305 message + if (!ad) adLen = 0; std::vector polyMsg(adLen + msgLen + 3*16); - size_t offset = 0; + size_t offset = 0; uint8_t padding[16]; memset (padding, 0, 16); - memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data - auto rem = adLen & 0x0F; // %16 - if (rem) - { - // padding1 - rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + if (ad) + { + memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data + auto rem = adLen & 0x0F; // %16 + if (rem) + { + // padding1 + rem = 16 - rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } } memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data - rem = msgLen & 0x0F; // %16 + auto rem = msgLen & 0x0F; // %16 if (rem) { // padding2 diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f7e5e796..4551a8cd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -20,7 +20,7 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), - m_NextReceivedBuffer (nullptr) + m_NextReceivedBuffer (nullptr), m_ReceiveSequenceNumber (0) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -470,7 +470,43 @@ namespace transport LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); Terminate (); } - Terminate (); // TODO + else + { + uint8_t nonce[12]; + memset (nonce, 0, 4); htole64buf (nonce + 4, m_ReceiveSequenceNumber); m_ReceiveSequenceNumber++; + uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_Kba, nonce, decrypted, m_NextReceivedLen, false)) // decrypt. assume Alice TODO: + { + LogPrint (eLogInfo, "NTCP2: received message decrypted"); + ProcessNextFrame (decrypted, m_NextReceivedLen-16); + ReceiveLength (); + } + else + { + LogPrint (eLogWarning, "NTCP2: Received MAC verification failed "); + Terminate (); + } + delete[] decrypted; + } + } + + void NTCP2Session::ProcessNextFrame (const uint8_t * frame, size_t len) + { + size_t offset = 0; + while (offset < len) + { + uint8_t blk = frame[offset]; + offset++; + auto size = bufbe16toh (frame + offset); + offset += 2; + LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size); + if (size > len) + { + LogPrint (eLogError, "NTCP2: Unexpected block length ", size); + break; + } + offset += size; + } } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5f8d116d..744b3375 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -55,6 +55,7 @@ namespace transport void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); void Receive (); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void ProcessNextFrame (const uint8_t * frame, size_t len); private: @@ -71,6 +72,7 @@ namespace transport uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer; uint8_t m_ReceiveIV[8]; + uint64_t m_ReceiveSequenceNumber; }; class NTCP2Server From 510d29b381511b5fb9278d9909fc216774cce381 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jun 2018 06:56:05 -0400 Subject: [PATCH 105/115] gcc 8 arch support --- Makefile.linux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.linux b/Makefile.linux index 2c30bbb0..cf045eb4 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -21,7 +21,7 @@ else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 NEEDED_CXXFLAGS += -std=c++0x else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0 NEEDED_CXXFLAGS += -std=c++11 -else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 ubuntu +else ifeq ($(shell expr match ${CXXVER} "[7-8]"),1) # gcc 7 ubuntu or gcc 8 arch NEEDED_CXXFLAGS += -std=c++11 else # not supported $(error Compiler too old) From 39eed0f6fbe8e1bae4b10c9dfddb105e5d2ad4df Mon Sep 17 00:00:00 2001 From: shak Date: Sat, 23 Jun 2018 23:52:16 +0000 Subject: [PATCH 106/115] Read explicitPeer config settings into params --- libi2pd_client/ClientContext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index b40c2832..f3ab3fd9 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -389,6 +389,7 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); + options[I2CP_PARAM_EXPLICIT_PEERS] = GetI2CPOption(section, I2CP_PARAM_EXPLICIT_PEERS, NULL); } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const @@ -406,6 +407,8 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_EXPLICIT_PEERS, value)) + options[I2CP_PARAM_EXPLICIT_PEERS] = value; } void ClientContext::ReadTunnels () From f0b32e3f54fa536667d54e7a28cf2c487e2e72cf Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jun 2018 06:46:22 -0400 Subject: [PATCH 107/115] Revert "Read explicitPeer config settings into params" --- libi2pd_client/ClientContext.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index f3ab3fd9..b40c2832 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -389,7 +389,6 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); - options[I2CP_PARAM_EXPLICIT_PEERS] = GetI2CPOption(section, I2CP_PARAM_EXPLICIT_PEERS, NULL); } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const @@ -407,8 +406,6 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; - if (i2p::config::GetOption(prefix + I2CP_PARAM_EXPLICIT_PEERS, value)) - options[I2CP_PARAM_EXPLICIT_PEERS] = value; } void ClientContext::ReadTunnels () From 5bc157eb190e5b64a087d56bdd24cef1778cc7f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Jun 2018 12:28:07 -0400 Subject: [PATCH 108/115] send data frame for NTCP2 --- libi2pd/NTCP2.cpp | 44 +++++++++++++++++++++++++++++++++++++++++--- libi2pd/NTCP2.h | 10 +++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 4551a8cd..594f4a93 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -20,7 +20,8 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), - m_NextReceivedBuffer (nullptr), m_ReceiveSequenceNumber (0) + m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), + m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -38,6 +39,7 @@ namespace transport delete[] m_SessionCreatedBuffer; delete[] m_SessionConfirmedBuffer; delete[] m_NextReceivedBuffer; + delete[] m_NextSendBuffer; } void NTCP2Session::Terminate () @@ -69,6 +71,12 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } + void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); + } + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { static const uint8_t protocolNameHash[] = @@ -378,7 +386,7 @@ namespace transport // part1 48 bytes m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; - memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 + CreateNonce (1, nonce); i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again @@ -411,7 +419,16 @@ namespace transport LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice + memcpy (m_SendIV, m_Sipkeysab + 16, 8); //Alice ReceiveLength (); + + // TODO: remove + uint8_t pad[1024]; + auto paddingLength = rand () % 1000; + RAND_bytes (pad + 3, paddingLength); + pad[0] = 254; + htobe16buf (pad + 1, paddingLength); + SendNextFrame (pad, paddingLength + 3); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -473,7 +490,7 @@ namespace transport else { uint8_t nonce[12]; - memset (nonce, 0, 4); htole64buf (nonce + 4, m_ReceiveSequenceNumber); m_ReceiveSequenceNumber++; + CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_Kba, nonce, decrypted, m_NextReceivedLen, false)) // decrypt. assume Alice TODO: { @@ -509,6 +526,27 @@ namespace transport } } + void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) + { + uint8_t nonce[12]; + CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; + m_NextSendBuffer = new uint8_t[len + 16 + 2]; + i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_Kab, nonce, m_NextSendBuffer + 2, len + 16, true); // encrypt. assume Alice TODO: + i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_Sipkeysab); // assume Alice TODO: + htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); + LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); + + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, len + 16 + 2), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; + LogPrint (eLogDebug, "NTCP2: Next frame sent"); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 744b3375..6ee76aad 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -31,6 +31,7 @@ namespace transport private: void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + void CreateNonce (uint64_t seqn, uint8_t * nonce); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 @@ -57,6 +58,9 @@ namespace transport void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void ProcessNextFrame (const uint8_t * frame, size_t len); + void SendNextFrame (const uint8_t * payload, size_t len); + void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: NTCP2Server& m_Server; @@ -70,9 +74,9 @@ namespace transport // data phase uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; uint16_t m_NextReceivedLen; - uint8_t * m_NextReceivedBuffer; - uint8_t m_ReceiveIV[8]; - uint64_t m_ReceiveSequenceNumber; + uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; + uint8_t m_ReceiveIV[8], m_SendIV[8]; + uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; }; class NTCP2Server From b226e22d2fead08013c23d13888c90429c29ea36 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 07:25:16 -0400 Subject: [PATCH 109/115] fixed QT build --- qt/i2pd_qt/DaemonQT.h | 1 + qt/i2pd_qt/i2pd_qt.pro | 3 +++ 2 files changed, 4 insertions(+) diff --git a/qt/i2pd_qt/DaemonQT.h b/qt/i2pd_qt/DaemonQT.h index 780d2f73..aa329f56 100644 --- a/qt/i2pd_qt/DaemonQT.h +++ b/qt/i2pd_qt/DaemonQT.h @@ -1,6 +1,7 @@ #ifndef DAEMONQT_H #define DAEMONQT_H +#include #include #include #include diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 6c0464ab..0488f289 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -66,6 +66,9 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../libi2pd/TunnelGateway.cpp \ ../../libi2pd/TunnelPool.cpp \ ../../libi2pd/util.cpp \ + ../../libi2pd/Ed25519.cpp \ + ../../libi2pd/Chacha20.cpp \ + ../../libi2pd/Poly1305.cpp \ ../../libi2pd_client/AddressBook.cpp \ ../../libi2pd_client/BOB.cpp \ ../../libi2pd_client/ClientContext.cpp \ From 27fbf6735222a6e7768b03c195b33fe9e0c382e7 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 18:07:06 +0300 Subject: [PATCH 110/115] add systemd configs, change build info, update changelog --- debian/changelog | 5 +++-- debian/control | 6 ++---- debian/i2pd.service | 1 + debian/i2pd.tmpfile | 2 ++ debian/rules | 10 +++++----- 5 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 debian/i2pd.service create mode 100644 debian/i2pd.tmpfile diff --git a/debian/changelog b/debian/changelog index 1b87e73c..230dd9a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,12 @@ -i2pd (2.19.0-pre1) unstable; urgency=low +i2pd (2.19.0-1) unstable; urgency=low * updated to version 2.19.0/0.9.35 * update manpage (1) * update docfiles * fixes in systemd unit (#1089, #1142, #1154, #1155) + * package now building with systemd support - -- R4SAS Wed, 20 Jun 2018 02:11:00 +0000 + -- R4SAS Tue, 26 Jun 2018 15:00:00 +0000 i2pd (2.18.0-1) unstable; urgency=low diff --git a/debian/control b/debian/control index 76d753d4..8ef0b08c 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: i2pd Section: net Priority: optional Maintainer: R4SAS -Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev, dh-apparmor +Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.17.2~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev Standards-Version: 3.9.6 Homepage: http://i2pd.website/ Vcs-Git: git://github.com/PurpleI2P/i2pd.git @@ -11,8 +11,7 @@ Vcs-Browser: https://github.com/PurpleI2P/i2pd Package: i2pd Architecture: any Pre-Depends: adduser -Depends: ${shlibs:Depends}, ${misc:Depends} -Suggests: tor, privoxy, apparmor +Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base, Description: Full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants @@ -25,7 +24,6 @@ Architecture: any Priority: extra Section: debug Depends: i2pd (= ${binary:Version}), ${misc:Depends} -Suggests: gdb Description: i2pd debugging symbols I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants diff --git a/debian/i2pd.service b/debian/i2pd.service new file mode 100644 index 00000000..ca477e3b --- /dev/null +++ b/debian/i2pd.service @@ -0,0 +1 @@ +../i2pd.service \ No newline at end of file diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile new file mode 100644 index 00000000..6cd19112 --- /dev/null +++ b/debian/i2pd.tmpfile @@ -0,0 +1,2 @@ +d /var/run/i2pd 0755 i2pd i2pd - - +d /var/log/i2pd 0755 i2pd i2pd - - diff --git a/debian/rules b/debian/rules index 4654ae6c..53244c56 100755 --- a/debian/rules +++ b/debian/rules @@ -5,14 +5,14 @@ #export DH_VERBOSE=1 DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/buildflags.mk -CXXFLAGS+=$(CPPFLAGS) -PREFIX=/usr +#DPKG_EXPORT_BUILDFLAGS = 1 +#include /usr/share/dpkg/buildflags.mk +#CXXFLAGS+=$(CPPFLAGS) +#PREFIX=/usr %: dh $@ --parallel - dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd + #dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd override_dh_strip: dh_strip --dbg-package=i2pd-dbg From a188de2e5cd627b6850dca2501084d6e3eed4bd9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 16:23:21 +0000 Subject: [PATCH 111/115] increase limits by default, fix symbolic links, change rules --- contrib/i2pd.service | 2 +- debian/i2pd.service | 2 +- debian/i2pd.tmpfile | 3 +-- debian/rules | 7 ++++--- 4 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 120000 debian/i2pd.service mode change 100644 => 120000 debian/i2pd.tmpfile diff --git a/contrib/i2pd.service b/contrib/i2pd.service index 3f53bfb8..debd49b0 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -24,7 +24,7 @@ KillSignal=SIGQUIT #TimeoutStopSec=10m # If you have problems with hanging i2pd, you can try enable this -#LimitNOFILE=4096 +LimitNOFILE=4096 PrivateDevices=yes [Install] diff --git a/debian/i2pd.service b/debian/i2pd.service deleted file mode 100644 index ca477e3b..00000000 --- a/debian/i2pd.service +++ /dev/null @@ -1 +0,0 @@ -../i2pd.service \ No newline at end of file diff --git a/debian/i2pd.service b/debian/i2pd.service new file mode 120000 index 00000000..57d6b4da --- /dev/null +++ b/debian/i2pd.service @@ -0,0 +1 @@ +../contrib/debian/i2pd.service \ No newline at end of file diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile deleted file mode 100644 index 6cd19112..00000000 --- a/debian/i2pd.tmpfile +++ /dev/null @@ -1,2 +0,0 @@ -d /var/run/i2pd 0755 i2pd i2pd - - -d /var/log/i2pd 0755 i2pd i2pd - - diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile new file mode 120000 index 00000000..22dfb4cf --- /dev/null +++ b/debian/i2pd.tmpfile @@ -0,0 +1 @@ +../contrib/debian/i2pd.tmpfile \ No newline at end of file diff --git a/debian/rules b/debian/rules index 53244c56..8e537049 100755 --- a/debian/rules +++ b/debian/rules @@ -12,10 +12,11 @@ DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow %: dh $@ --parallel - #dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd +# dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd override_dh_strip: dh_strip --dbg-package=i2pd-dbg -override_dh_shlibdeps: - dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info +## uncoment this if you have "missing info" problem when building package +#override_dh_shlibdeps: +# dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info From 34c45f26945445fcfbd7839738976a1bec2038e3 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 16:26:28 +0000 Subject: [PATCH 112/115] update debian changelog --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 230dd9a8..74c366d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,13 @@ -i2pd (2.19.0-1) unstable; urgency=low +i2pd (2.19.0-1) unstable; urgency=medium * updated to version 2.19.0/0.9.35 * update manpage (1) * update docfiles + * update build rules * fixes in systemd unit (#1089, #1142, #1154, #1155) * package now building with systemd support - -- R4SAS Tue, 26 Jun 2018 15:00:00 +0000 + -- R4SAS Tue, 26 Jun 2018 16:27:45 +0000 i2pd (2.18.0-1) unstable; urgency=low From 00df3f8d4e7b58c56d08936bc975f40c12b35e38 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 13:36:30 -0400 Subject: [PATCH 113/115] 2.19.0 --- ChangeLog | 25 +++++++++++++++++++++++++ Win32/installer.iss | 2 +- android/AndroidManifest.xml | 4 ++-- libi2pd/version.h | 4 ++-- qt/i2pd_qt/android/AndroidManifest.xml | 2 +- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index d2bfe7bf..54989d44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,31 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.19.0] - 2018-06-26 +### Added +- ECIES support for RouterInfo +- HTTP outproxy authorization +- AVX/AESNI runtime detection +- Initial implementation of NTCP2 +- I2CP session reconfigure +- I2CP method ClientServicesInfo +- Datagrams to websocks +### Changed +- RouterInfo uses EdDSA signature by default +- Remove stream bans +- Android build system changed to gradle +- Multiple changes in QT GUI +- Dockerfile +### Fixed +- zero tunnelID issue +- tunnels reload +- headers in webconsole +- XSS in webconsole from SAM session name +- build for gcc 8 +- cmake build scripts +- systemd service files +- some netbsd issues + ## [2.18.0] - 2018-01-30 ### Added - Show tunnel nicknames for I2CP destination in WebUI diff --git a/Win32/installer.iss b/Win32/installer.iss index 15ce4372..c4e1fffd 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.18.0" +#define I2Pd_ver "2.19.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index cfc9d55b..ca66c17d 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -3,7 +3,7 @@ package="org.purplei2p.i2pd" android:installLocation="auto" android:versionCode="1" - android:versionName="2.18.0"> + android:versionName="2.19.0"> - \ No newline at end of file + diff --git a/libi2pd/version.h b/libi2pd/version.h index e0443415..129035ad 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 18 +#define I2PD_VERSION_MINOR 19 #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 34 +#define I2P_VERSION_MICRO 35 #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/android/AndroidManifest.xml b/qt/i2pd_qt/android/AndroidManifest.xml index 56b37e6a..d98e24d4 100644 --- a/qt/i2pd_qt/android/AndroidManifest.xml +++ b/qt/i2pd_qt/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + From 0dff636dbe8b284da3e77483078b2681fb2aa6a3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 13:38:02 -0400 Subject: [PATCH 114/115] 2.19.0 --- contrib/rpm/i2pd.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 22c31192..1c07a887 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -96,6 +96,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Jun 26 2018 orignal - 2.19.0 +- update to 2.19.0 + * Mon Feb 05 2018 r4sas - 2.18.0-2 - Fixed blocking system shutdown for 10 minutes (#1089) From fc16e76af13b0ca5bd39b5768e71245bd74ae831 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 17:46:01 +0000 Subject: [PATCH 115/115] 2.19.0 --- android/build.gradle | 2 +- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 4 ++-- contrib/rpm/i2pd.spec | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index d58e098f..c5834e19 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -25,7 +25,7 @@ android { targetSdkVersion 25 minSdkVersion 14 versionCode 1 - versionName "2.18.0" + versionName "2.19.0" ndk { abiFilters 'armeabi-v7a' //abiFilters 'x86' diff --git a/appveyor.yml b/appveyor.yml index 68b74529..27f563ef 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.18.{build} +version: 2.19.{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 6e02779d..02986475 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.18.0 +Version: 2.19.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -99,4 +99,4 @@ getent passwd i2pd >/dev/null || \ %changelog * Thu Feb 01 2018 r4sas - 2.18.0 -- Initial i2pd-git based on i2pd 2.18.0-1 spec \ No newline at end of file +- Initial i2pd-git based on i2pd 2.18.0-1 spec diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 1c07a887..db480d35 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,6 +1,6 @@ Name: i2pd -Version: 2.18.0 -Release: 2%{?dist} +Version: 2.19.0 +Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git