From dec848f0721be8afd06a8c4c5e1dd97cb8476b2d Mon Sep 17 00:00:00 2001 From: yangfl Date: Wed, 27 Jun 2018 17:09:46 +0800 Subject: [PATCH 01/64] use builtin __AVX__ and __AES__ macros and reduce code duplication --- Makefile.homebrew | 2 +- Makefile.linux | 2 +- Makefile.mingw | 2 +- Makefile.osx | 2 +- build/CMakeLists.txt | 7 +- libi2pd/CPU.cpp | 14 +++- libi2pd/Crypto.cpp | 162 ++++++++++++++----------------------------- libi2pd/Crypto.h | 23 +++--- libi2pd/Identity.cpp | 39 ++++++----- 9 files changed, 104 insertions(+), 149 deletions(-) diff --git a/Makefile.homebrew b/Makefile.homebrew index a6e645ee..6830b051 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -34,7 +34,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index cf045eb4..e9609876 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index b40d0ada..fe897ae0 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 8bbf37f0..5752b2fe 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -21,7 +21,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes else CXXFLAGS += -msse endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 632edc03..bed5ee10 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories(${LIBI2PD_CLIENT_SRC_DIR}) set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/BloomFilter.cpp" "${LIBI2PD_SRC_DIR}/Config.cpp" - "${LIBI2PD_SRC_DIR}/CPU.cpp" + "${LIBI2PD_SRC_DIR}/CPU.cpp" "${LIBI2PD_SRC_DIR}/Crypto.cpp" "${LIBI2PD_SRC_DIR}/CryptoKey.cpp" "${LIBI2PD_SRC_DIR}/Garlic.cpp" @@ -77,10 +77,10 @@ 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}/ChaCha20.cpp" "${LIBI2PD_SRC_DIR}/Poly1305.cpp" "${LIBI2PD_SRC_DIR}/Ed25519.cpp" - "${LIBI2PD_SRC_DIR}/NTCP2.cpp" + "${LIBI2PD_SRC_DIR}/NTCP2.cpp" ) if (WITH_WEBSOCKETS) @@ -234,7 +234,6 @@ endif () if (WITH_AESNI) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes" ) - add_definitions ( -DAESNI ) endif() if (WITH_AVX) diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp index d2868a20..a707c3dc 100644 --- a/libi2pd/CPU.cpp +++ b/libi2pd/CPU.cpp @@ -21,23 +21,35 @@ namespace cpu void Detect() { +#if defined(__AES__) || defined(__AVX__) + #if defined(__x86_64__) || defined(__i386__) int info[4]; __cpuid(0, info[0], info[1], info[2], info[3]); if (info[0] >= 0x00000001) { __cpuid(0x00000001, info[0], info[1], info[2], info[3]); +#ifdef __AES__ aesni = info[2] & bit_AES; // AESNI +#endif // __AES__ +#ifdef __AVX__ avx = info[2] & bit_AVX; // AVX +#endif // __AVX__ } -#endif +#endif // defined(__x86_64__) || defined(__i386__) + +#ifdef __AES__ if(aesni) { LogPrint(eLogInfo, "AESNI enabled"); } +#endif // __AES__ +#ifdef __AVX__ if(avx) { LogPrint(eLogInfo, "AVX enabled"); } +#endif // __AVX__ +#endif // defined(__AES__) || defined(__AVX__) } } } diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 6d859342..24ce9c72 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -399,7 +399,7 @@ namespace crypto bn2buf (x, encrypted + 1, len); bn2buf (y, encrypted + 1 + len, len); RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len); - } + } else { bn2buf (x, encrypted, len); @@ -468,10 +468,10 @@ namespace crypto CBCDecryption decryption; decryption.SetKey (shared); decryption.SetIV (iv); - if (zeroPadding) + if (zeroPadding) decryption.Decrypt (encrypted + 258, 256, m); else - decryption.Decrypt (encrypted + 256, 256, m); + decryption.Decrypt (encrypted + 256, 256, m); // verify and copy uint8_t hash[32]; SHA256 (m + 33, 222, hash); @@ -522,9 +522,9 @@ namespace crypto { uint64_t buf[256]; uint64_t hash[12]; // 96 bytes +#ifdef __AVX__ if(i2p::cpu::avx) { -#ifdef AVX __asm__ ( "vmovups %[key], %%ymm0 \n" @@ -543,30 +543,9 @@ namespace crypto [buf]"r"(buf), [hash]"r"(hash) : "memory", "%xmm0" // TODO: change to %ymm0 later ); -#else - // ikeypad - buf[0] = key.GetLL ()[0] ^ IPAD; - buf[1] = key.GetLL ()[1] ^ IPAD; - buf[2] = key.GetLL ()[2] ^ IPAD; - buf[3] = key.GetLL ()[3] ^ IPAD; - buf[4] = IPAD; - buf[5] = IPAD; - buf[6] = IPAD; - buf[7] = IPAD; - // okeypad - hash[0] = key.GetLL ()[0] ^ OPAD; - hash[1] = key.GetLL ()[1] ^ OPAD; - hash[2] = key.GetLL ()[2] ^ OPAD; - hash[3] = key.GetLL ()[3] ^ OPAD; - hash[4] = OPAD; - hash[5] = OPAD; - hash[6] = OPAD; - hash[7] = OPAD; - // fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P) - memset (hash + 10, 0, 16); -#endif } else +#endif { // ikeypad buf[0] = key.GetLL ()[0] ^ IPAD; @@ -600,12 +579,12 @@ namespace crypto } // AES -#ifdef AESNI +#ifdef __AES__ #ifdef ARM64AES void init_aesenc(void){ // TODO: Implementation } - + #endif #define KeyExpansion256(round0,round1) \ @@ -632,7 +611,7 @@ namespace crypto "movaps %%xmm3, "#round1"(%[sched]) \n" #endif -#ifdef AESNI +#ifdef __AES__ void ECBCryptoAESNI::ExpandKey (const AESKey& key) { __asm__ @@ -669,11 +648,11 @@ namespace crypto : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged ); - } + } #endif -#if AESNI +#ifdef __AES__ #define EncryptAES256(sched) \ "pxor (%["#sched"]), %%xmm0 \n" \ "aesenc 16(%["#sched"]), %%xmm0 \n" \ @@ -691,12 +670,12 @@ namespace crypto "aesenc 208(%["#sched"]), %%xmm0 \n" \ "aesenclast 224(%["#sched"]), %%xmm0 \n" #endif - + void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[in]), %%xmm0 \n" @@ -704,17 +683,15 @@ namespace crypto "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); -#else - AES_encrypt (in->buf, out->buf, &m_Key); -#endif } else +#endif { AES_encrypt (in->buf, out->buf, &m_Key); - } + } } -#ifdef AESNI +#ifdef __AES__ #define DecryptAES256(sched) \ "pxor 224(%["#sched"]), %%xmm0 \n" \ "aesdec 208(%["#sched"]), %%xmm0 \n" \ @@ -732,12 +709,12 @@ namespace crypto "aesdec 16(%["#sched"]), %%xmm0 \n" \ "aesdeclast (%["#sched"]), %%xmm0 \n" #endif - + void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[in]), %%xmm0 \n" @@ -745,17 +722,15 @@ namespace crypto "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); -#else - AES_decrypt (in->buf, out->buf, &m_Key); -#endif } else +#endif { AES_decrypt (in->buf, out->buf, &m_Key); } } -#ifdef AESNI +#ifdef __AES__ #define CallAESIMC(offset) \ "movaps "#offset"(%[shed]), %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \ @@ -764,25 +739,23 @@ namespace crypto void ECBEncryption::SetKey (const AESKey& key) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI - ExpandKey (key); -#else - AES_set_encrypt_key (key, 256, &m_Key); -#endif + ExpandKey (key); } else +#endif { AES_set_encrypt_key (key, 256, &m_Key); } } - + void ECBDecryption::SetKey (const AESKey& key) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI ExpandKey (key); // expand encryption key first // then invert it using aesimc __asm__ @@ -802,11 +775,9 @@ namespace crypto CallAESIMC(208) : : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory" ); -#else - AES_set_decrypt_key (key, 256, &m_Key); -#endif } else +#endif { AES_set_decrypt_key (key, 256, &m_Key); } @@ -815,9 +786,9 @@ namespace crypto void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -837,16 +808,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "cc", "memory" ); -#else - for (int i = 0; i < numBlocks; i++) - { - *m_LastBlock.GetChipherBlock () ^= in[i]; - m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); - out[i] = *m_LastBlock.GetChipherBlock (); - } -#endif } else +#endif { for (int i = 0; i < numBlocks; i++) { @@ -867,9 +831,9 @@ namespace crypto void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -883,19 +847,17 @@ namespace crypto [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); -#else - Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); -#endif } else +#endif Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); } void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -916,17 +878,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); -#else - for (int i = 0; i < numBlocks; i++) - { - ChipherBlock tmp = in[i]; - m_ECBDecryption.Decrypt (in + i, out + i); - out[i] ^= *m_IV.GetChipherBlock (); - *m_IV.GetChipherBlock () = tmp; - } -#endif } else +#endif { for (int i = 0; i < numBlocks; i++) { @@ -947,9 +901,9 @@ namespace crypto void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -963,19 +917,17 @@ namespace crypto [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); -#else - Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); -#endif } else +#endif Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); } void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( // encrypt IV @@ -1001,14 +953,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "cc", "memory" ); -#else - m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerEncryption.SetIV (out); - m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv -#endif } else +#endif { m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerEncryption.SetIV (out); @@ -1019,9 +966,9 @@ namespace crypto void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( // decrypt IV @@ -1048,14 +995,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); -#else - m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerDecryption.SetIV (out); - m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv -#endif } else +#endif { m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerDecryption.SetIV (out); @@ -1068,7 +1010,7 @@ 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 (len < msgLen) return false; + if (len < msgLen) return false; if (encrypt && len < msgLen + 16) return false; bool ret = true; #if LEGACY_OPENSSL @@ -1076,40 +1018,40 @@ namespace crypto uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); chacha20 (polyKey, 64, nonce, key, 0); - // encrypt data + // encrypt data memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); - + // create Poly1305 message - if (!ad) adLen = 0; + if (!ad) adLen = 0; std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; uint8_t padding[16]; memset (padding, 0, 16); if (ad) - { + { memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data auto rem = adLen & 0x0F; // %16 - if (rem) + if (rem) { // padding1 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } } memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data auto rem = msgLen & 0x0F; // %16 - if (rem) + if (rem) { // padding2 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } - htole64buf (polyMsg.data () + offset, adLen); offset += 8; + htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; if (encrypt) { - // calculate Poly1305 tag and write in after encrypted data + // calculate Poly1305 tag and write in after encrypted data Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); } else @@ -1118,9 +1060,9 @@ namespace crypto // calculate Poly1305 tag Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided - } + } #else - int outlen = 0; + int outlen = 0; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); if (encrypt) { @@ -1141,8 +1083,8 @@ namespace crypto EVP_DecryptUpdate(ctx, NULL, &outlen, ad, adLen); ret = EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen) > 0; } - - EVP_CIPHER_CTX_free (ctx); + + EVP_CIPHER_CTX_free (ctx); #endif return ret; } diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 25646dbb..fe0fcddf 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -69,9 +69,9 @@ namespace crypto void operator^=(const ChipherBlock& other) // XOR { +#ifdef __AVX__ if (i2p::cpu::avx) { -#ifdef AVX __asm__ ( "vmovups (%[buf]), %%xmm0 \n" @@ -82,12 +82,9 @@ namespace crypto : [buf]"r"(buf), [other]"r"(other.buf) : "%xmm0", "%xmm1", "memory" ); -#else - for (int i = 0; i < 16; i++) - buf[i] ^= other.buf[i]; -#endif } else +#endif { // TODO: implement it better for (int i = 0; i < 16; i++) @@ -123,7 +120,7 @@ namespace crypto }; -#ifdef AESNI +#ifdef __AES__ #ifdef ARM64AES void init_aesenc(void) __attribute__((constructor)); #endif @@ -143,7 +140,7 @@ namespace crypto }; #endif -#ifdef AESNI +#ifdef __AES__ class ECBEncryption: public ECBCryptoAESNI #else class ECBEncryption @@ -152,14 +149,14 @@ namespace crypto public: void SetKey (const AESKey& key); - + void Encrypt(const ChipherBlock * in, ChipherBlock * out); private: AES_KEY m_Key; }; -#ifdef AESNI +#ifdef __AES__ class ECBDecryption: public ECBCryptoAESNI #else class ECBDecryption @@ -188,7 +185,7 @@ namespace crypto void Encrypt (const uint8_t * in, uint8_t * out); // one block ECBEncryption & ECB() { return m_ECBEncryption; } - + private: AESAlignedBuffer<16> m_LastBlock; @@ -211,7 +208,7 @@ namespace crypto void Decrypt (const uint8_t * in, uint8_t * out); // one block ECBDecryption & ECB() { return m_ECBDecryption; } - + private: AESAlignedBuffer<16> m_IV; @@ -255,8 +252,8 @@ namespace crypto }; // AEAD/ChaCha20/Poly1305 - 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 - + 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); void TerminateCrypto (); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 3fcd16ad..7f64d931 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -719,24 +719,29 @@ namespace data XORMetric operator^(const IdentHash& key1, const IdentHash& key2) { XORMetric m; -#if defined(__AVX__) // for AVX - __asm__ - ( - "vmovups %1, %%ymm0 \n" - "vmovups %2, %%ymm1 \n" - "vxorps %%ymm0, %%ymm1, %%ymm1 \n" - "vmovups %%ymm1, %0 \n" - : "=m"(*m.metric) - : "m"(*key1), "m"(*key2) - : "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler - ); -#else - const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); - m.metric_ll[0] = hash1[0] ^ hash2[0]; - m.metric_ll[1] = hash1[1] ^ hash2[1]; - m.metric_ll[2] = hash1[2] ^ hash2[2]; - m.metric_ll[3] = hash1[3] ^ hash2[3]; +#ifdef __AVX__ + if(i2p::cpu::avx) + { + __asm__ + ( + "vmovups %1, %%ymm0 \n" + "vmovups %2, %%ymm1 \n" + "vxorps %%ymm0, %%ymm1, %%ymm1 \n" + "vmovups %%ymm1, %0 \n" + : "=m"(*m.metric) + : "m"(*key1), "m"(*key2) + : "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler + ); + } + else #endif + { + const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); + m.metric_ll[0] = hash1[0] ^ hash2[0]; + m.metric_ll[1] = hash1[1] ^ hash2[1]; + m.metric_ll[2] = hash1[2] ^ hash2[2]; + m.metric_ll[3] = hash1[3] ^ hash2[3]; + } return m; } From 41e8ab53835eb599243856001adbeb314f106658 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Jun 2018 17:47:22 +0300 Subject: [PATCH 02/64] Limit tampering with standard C++ library to Linux Otherwise it breaks e.g. FreeBSD build where it is not needed at all --- build/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index bed5ee10..73e76ae0 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -202,9 +202,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif () elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # more tweaks - if (NOT (MSVC OR MSYS OR APPLE)) + if (LINUX) set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libstdc++" ) # required for list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++") # required to link with -stdlib=libstdc++ + endif() + if (NOT (MSVC OR MSYS OR APPLE)) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" ) endif() endif () From 4ffbb46cf9c63dfddc062771a9bb29a5d50524af Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Jun 2018 22:31:01 +0300 Subject: [PATCH 03/64] Fix "macro expansion producing 'defined' has undefined behavior" clang warning --- libi2pd/Crypto.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index fe0fcddf..43f1def9 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -262,7 +262,12 @@ namespace crypto // take care about openssl version #include -#define LEGACY_OPENSSL ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +#if ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +# define LEGACY_OPENSSL 1 +#else +# define LEGACY_OPENSSL 0 +#endif + #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 db5b45222a7c8f9f4e4beacccce133c15ba097fc Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jun 2018 23:20:02 +0300 Subject: [PATCH 04/64] store and install assets on android --- android/build.gradle | 1 + .../src/org/purplei2p/i2pd/I2PDActivity.java | 492 ++++++++++-------- 2 files changed, 284 insertions(+), 209 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index c5834e19..683f3d27 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,6 +37,7 @@ android { java.srcDirs = ['src'] res.srcDirs = ['res'] jniLibs.srcDirs = ['libs'] + assets.srcDirs = ['assets'] } } signingConfigs { diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 99672eb7..28e30251 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -1,5 +1,10 @@ package org.purplei2p.i2pd; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Timer; @@ -10,7 +15,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.res.AssetManager; import android.os.Bundle; +import android.os.Environment; import android.os.IBinder; import android.util.Log; import android.view.Menu; @@ -19,24 +26,24 @@ import android.widget.TextView; import android.widget.Toast; public class I2PDActivity extends Activity { - private static final String TAG = "i2pdActvt"; - public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; - - private TextView textView; - + private static final String TAG = "i2pdActvt"; + public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; + + private TextView textView; + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); - + private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = - new DaemonSingleton.StateUpdateListener() { - + new DaemonSingleton.StateUpdateListener() { + @Override public void daemonStateUpdate() { runOnUiThread(new Runnable(){ - + @Override public void run() { try { - if(textView==null)return; + if(textView==null) return; Throwable tr = daemon.getLastThrowable(); if(tr!=null) { textView.setText(throwableToString(tr)); @@ -44,242 +51,309 @@ public class I2PDActivity extends Activity { } DaemonSingleton.State state = daemon.getState(); textView.setText( - String.valueOf(state)+ - (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ - (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") - ); - } catch (Throwable tr) { + String.valueOf(state)+ + (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ + (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") + ); + } catch (Throwable tr) { Log.e(TAG,"error ignored",tr); } } }); } }; - private static volatile long graceStartedMillis; - private static final Object graceStartedMillis_LOCK=new Object(); - - private static String formatGraceTimeRemaining() { - long remainingSeconds; - synchronized (graceStartedMillis_LOCK){ - remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); - } - long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); - long remSec=remainingSeconds-remainingMinutes*60; - return remainingMinutes+":"+(remSec/10)+remSec%10; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - textView = new TextView(this); - setContentView(textView); - daemon.addStateChangeListener(daemonStateUpdatedListener); - daemonStateUpdatedListener.daemonStateUpdate(); - - //set the app be foreground - doBindService(); - - final Timer gracefulQuitTimer = getGracefulQuitTimer(); - if(gracefulQuitTimer!=null){ - long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; - } - rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); - } - } - - @Override + private static volatile long graceStartedMillis; + private static final Object graceStartedMillis_LOCK=new Object(); + + private static String formatGraceTimeRemaining() { + long remainingSeconds; + synchronized (graceStartedMillis_LOCK){ + remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); + } + long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); + long remSec=remainingSeconds-remainingMinutes*60; + return remainingMinutes+":"+(remSec/10)+remSec%10; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // copy assets + copyAsset("certificates"); + copyAsset("i2pd.conf"); + copyAsset("subsciptions.txt"); + copyAsset("tunnels.conf"); + + textView = new TextView(this); + setContentView(textView); + daemon.addStateChangeListener(daemonStateUpdatedListener); + daemonStateUpdatedListener.daemonStateUpdate(); + + // set the app be foreground + doBindService(); + + final Timer gracefulQuitTimer = getGracefulQuitTimer(); + if(gracefulQuitTimer!=null){ + long gracefulStopAtMillis; + synchronized (graceStartedMillis_LOCK) { + gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + } + rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); + } + } + + @Override protected void onDestroy() { super.onDestroy(); - textView = null; - daemon.removeStateChangeListener(daemonStateUpdatedListener); - //cancelGracefulStop(); + textView = null; + daemon.removeStateChangeListener(daemonStateUpdatedListener); + //cancelGracefulStop(); try{ - doUnbindService(); - }catch(Throwable tr){ + doUnbindService(); + }catch(Throwable tr){ Log.e(TAG, "", tr); } } - - private static void cancelGracefulStop() { - Timer gracefulQuitTimer = getGracefulQuitTimer(); - if(gracefulQuitTimer!=null) { - gracefulQuitTimer.cancel(); - setGracefulQuitTimer(null); - } - } - - private CharSequence throwableToString(Throwable tr) { - StringWriter sw = new StringWriter(8192); - PrintWriter pw = new PrintWriter(sw); - tr.printStackTrace(pw); - pw.close(); - return sw.toString(); + + private static void cancelGracefulStop() { + Timer gracefulQuitTimer = getGracefulQuitTimer(); + if(gracefulQuitTimer!=null) { + gracefulQuitTimer.cancel(); + setGracefulQuitTimer(null); + } } - -// private LocalService mBoundService; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - // This is called when the connection with the service has been - // established, giving us the service object we can use to - // interact with the service. Because we have bound to a explicit - // service that we know is running in our own process, we can - // cast its IBinder to a concrete class and directly access it. -// mBoundService = ((LocalService.LocalBinder)service).getService(); - - // Tell the user about this for our demo. -// Toast.makeText(Binding.this, R.string.local_service_connected, -// Toast.LENGTH_SHORT).show(); - } - - public void onServiceDisconnected(ComponentName className) { - // This is called when the connection with the service has been - // unexpectedly disconnected -- that is, its process crashed. - // Because it is running in our same process, we should never - // see this happen. -// mBoundService = null; -// Toast.makeText(Binding.this, R.string.local_service_disconnected, -// Toast.LENGTH_SHORT).show(); - } - }; - - - private static volatile boolean mIsBound; - - private void doBindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) return; - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - } - - private void doUnbindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - } - } - } - + + private CharSequence throwableToString(Throwable tr) { + StringWriter sw = new StringWriter(8192); + PrintWriter pw = new PrintWriter(sw); + tr.printStackTrace(pw); + pw.close(); + return sw.toString(); + } + + // private LocalService mBoundService; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the service object we can use to + // interact with the service. Because we have bound to a explicit + // service that we know is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + // mBoundService = ((LocalService.LocalBinder)service).getService(); + + // Tell the user about this for our demo. + // Toast.makeText(Binding.this, R.string.local_service_connected, + // Toast.LENGTH_SHORT).show(); + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + // Because it is running in our same process, we should never + // see this happen. + // mBoundService = null; + // Toast.makeText(Binding.this, R.string.local_service_disconnected, + // Toast.LENGTH_SHORT).show(); + } + }; + + + private static volatile boolean mIsBound; + + private void doBindService() { + synchronized (I2PDActivity.class) { + if (mIsBound) return; + // Establish a connection with the service. We use an explicit + // class name because we want a specific service implementation that + // we know will be running in our own process (and thus won't be + // supporting component replacement by other applications). + bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + } + + private void doUnbindService() { + synchronized (I2PDActivity.class) { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); return true; } - + @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - + switch(id){ - case R.id.action_stop: - i2pdStop(); - return true; - case R.id.action_graceful_stop: - i2pdGracefulStop(); - return true; - } - + case R.id.action_stop: + i2pdStop(); + return true; + case R.id.action_graceful_stop: + i2pdGracefulStop(); + return true; + } + return super.onOptionsItemSelected(item); } - + private void i2pdStop() { - cancelGracefulStop(); - new Thread(new Runnable(){ - - @Override - public void run() { - Log.d(TAG, "stopping"); - try{ - daemon.stopDaemon(); - }catch (Throwable tr) { - Log.e(TAG, "", tr); - } - } - - },"stop").start(); - } - - private static volatile Timer gracefulQuitTimer; - - private void i2pdGracefulStop() { - if(daemon.getState()==DaemonSingleton.State.stopped){ - Toast.makeText(this, R.string.already_stopped, - Toast.LENGTH_SHORT).show(); - return; - } - if(getGracefulQuitTimer()!=null){ - Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, - Toast.LENGTH_SHORT).show(); - return; - } - Toast.makeText(this, R.string.graceful_stop_is_in_progress, - Toast.LENGTH_SHORT).show(); - new Thread(new Runnable(){ - + cancelGracefulStop(); + new Thread(new Runnable(){ + + @Override + public void run() { + Log.d(TAG, "stopping"); + try{ + daemon.stopDaemon(); + }catch (Throwable tr) { + Log.e(TAG, "", tr); + } + } + + },"stop").start(); + } + + private static volatile Timer gracefulQuitTimer; + + private void i2pdGracefulStop() { + if(daemon.getState()==DaemonSingleton.State.stopped){ + Toast.makeText(this, R.string.already_stopped, + Toast.LENGTH_SHORT).show(); + return; + } + if(getGracefulQuitTimer()!=null){ + Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, + Toast.LENGTH_SHORT).show(); + return; + } + Toast.makeText(this, R.string.graceful_stop_is_in_progress, + Toast.LENGTH_SHORT).show(); + new Thread(new Runnable(){ + @Override public void run() { try{ Log.d(TAG, "grac stopping"); - if(daemon.isStartedOkay()) { - daemon.stopAcceptingTunnels(); - long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - graceStartedMillis = System.currentTimeMillis(); - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; - } - rescheduleGraceStop(null,gracefulStopAtMillis); - }else{ - i2pdStop(); - } - } catch(Throwable tr) { + if(daemon.isStartedOkay()) { + daemon.stopAcceptingTunnels(); + long gracefulStopAtMillis; + synchronized (graceStartedMillis_LOCK) { + graceStartedMillis = System.currentTimeMillis(); + gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + } + rescheduleGraceStop(null,gracefulStopAtMillis); + }else{ + i2pdStop(); + } + } catch(Throwable tr) { Log.e(TAG,"",tr); } } - - },"gracInit").start(); - } - - private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { - if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); - final Timer gracefulQuitTimer = new Timer(true); - setGracefulQuitTimer(gracefulQuitTimer); - gracefulQuitTimer.schedule(new TimerTask(){ - - @Override - public void run() { - i2pdStop(); - } - - }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); - final TimerTask tickerTask = new TimerTask() { - @Override - public void run() { - daemonStateUpdatedListener.daemonStateUpdate(); - } - }; - gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); - } - - private static Timer getGracefulQuitTimer() { - return gracefulQuitTimer; + + },"gracInit").start(); } - + + private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { + if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); + final Timer gracefulQuitTimer = new Timer(true); + setGracefulQuitTimer(gracefulQuitTimer); + gracefulQuitTimer.schedule(new TimerTask(){ + + @Override + public void run() { + i2pdStop(); + } + + }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); + final TimerTask tickerTask = new TimerTask() { + @Override + public void run() { + daemonStateUpdatedListener.daemonStateUpdate(); + } + }; + gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); + } + + private static Timer getGracefulQuitTimer() { + return gracefulQuitTimer; + } + private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { - I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + } + + /** + * Copy the asset at the specified path to this app's data directory. If the + * asset is a directory, its contents are also copied. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyAsset(String path) { + AssetManager manager = getAssets(); + + // If we have a directory, we make it and recurse. If a file, we copy its + // contents. + try { + String[] contents = manager.list(path); + + // The documentation suggests that list throws an IOException, but doesn't + // say under what conditions. It'd be nice if it did so when the path was + // to a file. That doesn't appear to be the case. If the returned array is + // null or has 0 length, we assume the path is to a file. This means empty + // directories will get turned into files. + if (contents == null || contents.length == 0) + throw new IOException(); + + // Make the directory. + File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + dir.mkdirs(); + + // Recurse on the contents. + for (String entry : contents) { + copyAsset(path + "/" + entry); + } + } catch (IOException e) { + copyFileAsset(path); + } + } + + /** + * Copy the asset file specified by path to app's data directory. Assumes + * parent directories have already been created. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyFileAsset(String path) { + File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + try { + InputStream in = getAssets().open(path); + OutputStream out = new FileOutputStream(file); + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + while (read != -1) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + out.close(); + in.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } } } From 5233e7220586a1ddf809a979e338b754fd5761a0 Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 27 Jun 2018 23:43:49 +0300 Subject: [PATCH 05/64] add assets symlinks --- android/assets/certificates | 1 + android/assets/i2pd.conf | 1 + android/assets/subscriptions.txt | 1 + android/assets/tunnels.conf | 1 + 4 files changed, 4 insertions(+) create mode 120000 android/assets/certificates create mode 120000 android/assets/i2pd.conf create mode 120000 android/assets/subscriptions.txt create mode 120000 android/assets/tunnels.conf diff --git a/android/assets/certificates b/android/assets/certificates new file mode 120000 index 00000000..01b21e5d --- /dev/null +++ b/android/assets/certificates @@ -0,0 +1 @@ +../../contrib/certificates \ No newline at end of file diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf new file mode 120000 index 00000000..f4a68aa2 --- /dev/null +++ b/android/assets/i2pd.conf @@ -0,0 +1 @@ +../../contrib/i2pd.conf \ No newline at end of file diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt new file mode 120000 index 00000000..4fcc444f --- /dev/null +++ b/android/assets/subscriptions.txt @@ -0,0 +1 @@ +../../contrib/subscriptions.txt \ No newline at end of file diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf new file mode 120000 index 00000000..08767c73 --- /dev/null +++ b/android/assets/tunnels.conf @@ -0,0 +1 @@ +../../contrib/tunnels.conf \ No newline at end of file From 64aee9c8ae00a37ab4809766b7dde47f7cfeed44 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 29 Jun 2018 02:27:19 +0300 Subject: [PATCH 06/64] add DEBUG option for make By default, binary will be built without stripping debug symbols --- Makefile | 8 ++++++++ Makefile.bsd | 4 ++-- Makefile.homebrew | 7 ++++--- Makefile.linux | 8 ++++---- Makefile.mingw | 6 +++--- Makefile.osx | 7 +++---- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 6d56ec7d..c51018f9 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,14 @@ USE_AVX := yes USE_STATIC := no USE_MESHNET := no USE_UPNP := no +DEBUG := yes + +ifeq ($(DEBUG),yes) + CXX_DEBUG = -g +else + CXX_DEBUG = -Os + LD_DEBUG = -s +endif ifeq ($(WEBSOCKETS),1) NEEDED_CXXFLAGS += -DWITH_EVENTS diff --git a/Makefile.bsd b/Makefile.bsd index f2293540..39e5651a 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -1,5 +1,5 @@ CXX = clang++ -CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation ## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. ## For example, when adding 'hardening flags' to the build @@ -8,5 +8,5 @@ CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-ind ## custom FLAGS to work at build-time. NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ -LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread diff --git a/Makefile.homebrew b/Makefile.homebrew index 6830b051..41a89e93 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -3,8 +3,9 @@ BREWROOT = /usr/local BOOSTROOT = ${BREWROOT}/opt/boost SSLROOT = ${BREWROOT}/opt/libressl UPNPROOT = ${BREWROOT}/opt/miniupnpc -CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual +CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include +LDFLAGS = ${LD_DEBUG} ifndef TRAVIS CXX = clang++ @@ -13,7 +14,7 @@ endif ifeq ($(USE_STATIC),yes) LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread else - LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib + LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread endif @@ -34,7 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes + CXXFLAGS += -maes -DAESNI endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index e9609876..bd8d8fd3 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,13 +1,13 @@ # set defaults instead redefine -CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -INCFLAGS ?= +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation +LDFLAGS ?= ${LD_DEBUG} ## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. ## For example, when adding 'hardening flags' to the build ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## -std=c++11. If you want to remove this variable please do so in a way that allows setting -## custom FLAGS to work at build-time. +## custom FDLAGS to work at build-time. # detect proper flag for c++11 support by compilers CXXVER := $(shell $(CXX) -dumpversion) @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes + CPU_FLAGS += -maes -DAESNI endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index fe897ae0..ac2d0363 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,11 +1,11 @@ USE_WIN32_APP=yes CXX = g++ WINDRES = windres -CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN NEEDED_CXXFLAGS = -std=c++11 BOOST_SUFFIX = -mt INCFLAGS = -Idaemon -I. -LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ +LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ # UPNP Support ifeq ($(USE_UPNP),yes) @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes + CPU_FLAGS += -maes -DAESNI else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 5752b2fe..2db88784 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -1,8 +1,7 @@ CXX = clang++ -CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX -#CXXFLAGS = -g -O2 -Wall -std=c++11 +CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX INCFLAGS = -I/usr/local/include -LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDFLAGS := ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib ifeq ($(USE_STATIC),yes) LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread @@ -21,7 +20,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes + CXXFLAGS += -maes -DAESNI else CXXFLAGS += -msse endif From 55af4ed385ce0e5d2242f6ca8ae72439b8722665 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 29 Jun 2018 02:30:03 +0300 Subject: [PATCH 07/64] delete old AESNI definition --- Makefile.homebrew | 2 +- Makefile.linux | 2 +- Makefile.mingw | 2 +- Makefile.osx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.homebrew b/Makefile.homebrew index 41a89e93..688fdaea 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -35,7 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index bd8d8fd3..b9a740ad 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index ac2d0363..5dae3723 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 2db88784..3358cb10 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -20,7 +20,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes else CXXFLAGS += -msse endif From 6054bd6621a6c8e1bc6e611da07c2447b03b56be Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jul 2018 16:26:02 -0400 Subject: [PATCH 08/64] NTCP2 session establisher --- libi2pd/NTCP2.cpp | 197 +++++++++++++++++++++++----------------------- libi2pd/NTCP2.h | 27 +++++-- 2 files changed, 118 insertions(+), 106 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 594f4a93..5938d232 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -15,6 +15,73 @@ namespace i2p { namespace transport { + void NTCP2Establisher::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 NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) + { + 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); + // h = SHA256(h || pub) + memcpy (h + 32, pub, 32); + SHA256 (h, 64, m_H); + // x25519 between rs and priv + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Establisher::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); + memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = sessionRequestLen - 64; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), h, 32); + memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); + 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]; + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Establisher::CreateEphemeralKey (uint8_t * pub) + { + RAND_bytes (m_EphemeralPrivateKey, 32); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, m_Ctx); + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), @@ -23,11 +90,12 @@ namespace transport m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) { + m_Establisher.reset (new NTCP2Establisher); auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) { - memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_IV, addr->ntcp2->iv, 16); + memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); } else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); @@ -58,90 +126,26 @@ 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::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[] = - { - 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); - // h = SHA256(h || pub) - memcpy (h + 32, pub, 32); - SHA256 (h, 64, m_H); - // x25519 between rs and priv - uint8_t inputKeyMaterial[32]; - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, ctx); // rs*priv - BN_CTX_free (ctx); - MixKey (inputKeyMaterial, 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); - memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, h); - int paddingLength = sessionRequestLen - 64; - if (paddingLength > 0) - { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - 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 (); - i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, ctx); - BN_CTX_free (ctx); - 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); + i2p::crypto::GetEd25519 ()->ScalarMul (m_Establisher->m_Y, staticPrivKey, inputKeyMaterial, ctx); BN_CTX_free (ctx); - MixKey (inputKeyMaterial, derived); + m_Establisher->MixKey (inputKeyMaterial, derived); } void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) + HMAC(EVP_sha256(), m_Establisher->GetCK (), 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; @@ -149,7 +153,7 @@ namespace transport 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, m_Establisher->GetH (), 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)) @@ -159,13 +163,6 @@ namespace transport 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) - { - RAND_bytes (m_EphemeralPrivateKey, 32); - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, ctx); - BN_CTX_free (ctx); - } void NTCP2Session::SendSessionRequest () { @@ -176,16 +173,16 @@ namespace transport RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // generate key pair (X) uint8_t x[32]; - CreateEphemeralKey (x); + m_Establisher->CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_IV); + encryption.SetIV (m_Establisher->m_IV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); - encryption.GetIV (m_IV); // save IV for SessionCreated + encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key); + m_Establisher->KeyDerivationFunction1 (m_Establisher->m_RemoteStaticKey, m_Establisher->m_EphemeralPrivateKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -198,7 +195,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message 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)); @@ -235,15 +232,15 @@ namespace transport 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.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->m_Y); + decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Y, key); + m_Establisher->KeyDerivationFunction1 (m_Establisher->m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Establisher->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 + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, key, nonce, options, 16, false)) // decrypt { if (options[1] == 2) { @@ -286,14 +283,14 @@ namespace transport m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // generate key pair (y) uint8_t y[32]; - CreateEphemeralKey (y); + m_Establisher->CreateEphemeralKey (y); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_IV); + encryption.SetIV (m_Establisher->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); + m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -302,7 +299,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->m_H, 32, m_Establisher->m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message @@ -324,15 +321,15 @@ namespace transport // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - decryption.SetIV (m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); + decryption.SetIV (m_Establisher->m_IV); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->m_Y); // decryption key for next block (m_K) - KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->m_K, nonce, payload, 16, false)) // decrypt { uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); @@ -372,7 +369,7 @@ namespace transport { // update AD uint8_t h[80]; - memcpy (h, m_H, 32); + memcpy (h, m_Establisher->GetH (), 32); memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); int paddingLength = m_SessionCreatedBufferLen - 64; @@ -387,11 +384,11 @@ namespace transport m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_H); + SHA256 (h, 80, m_Establisher->m_H); size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; std::vector buf(m3p2Len - 16); @@ -402,11 +399,11 @@ namespace transport uint8_t key[32]; 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 + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 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 + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); memcpy (m_SessionConfirmedBuffer, tmp, 48); // send message diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 6ee76aad..38b7caf1 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "RouterInfo.h" #include "TransportSession.h" @@ -12,6 +13,25 @@ namespace i2p { namespace transport { + struct NTCP2Establisher + { + NTCP2Establisher () { m_Ctx = BN_CTX_new (); }; + ~NTCP2Establisher () { BN_CTX_free (m_Ctx); }; + + const uint8_t * GetCK () const { return m_CK; }; + const uint8_t * GetH () const { return m_H; }; + + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + 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 CreateEphemeralKey (uint8_t * pub); + + BN_CTX * m_Ctx; + 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 */; + + }; + class NTCP2Server; class NTCP2Session: public TransportSession, public std::enable_shared_from_this { @@ -30,15 +50,11 @@ 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 void KeyDerivationFunctionDataPhase (); // establish - void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void SendSessionCreated (); void SendSessionConfirmed (); @@ -67,8 +83,7 @@ namespace transport boost::asio::ip::tcp::socket m_Socket; bool m_IsEstablished, m_IsTerminated; - 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 */; + std::unique_ptr m_Establisher; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase From 5218c8584f37a0a89a95721637995c1cf1f4f1f9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Jul 2018 14:15:40 -0400 Subject: [PATCH 09/64] some refactoring of NTCP2 code --- libi2pd/NTCP2.cpp | 110 +++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 26 +++++++---- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 5938d232..f0d15926 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -15,6 +15,17 @@ namespace i2p { namespace transport { + NTCP2Establisher::NTCP2Establisher () + { + m_Ctx = BN_CTX_new (); + CreateEphemeralKey (); + } + + NTCP2Establisher::~NTCP2Establisher () + { + BN_CTX_free (m_Ctx); + } + void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) { // temp_key = HMAC-SHA256(ck, input_key_material) @@ -28,7 +39,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) + void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub) { static const uint8_t protocolNameHash[] = { @@ -50,10 +61,20 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv - MixKey (inputKeyMaterial, derived); + MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + void NTCP2Establisher::KDF1Alice () + { + KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ()); + } + + void NTCP2Establisher::KDF1Bob () + { + KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), GetRemotePub ()); + } + + void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) { uint8_t h[64]; memcpy (h, m_H, 32); @@ -62,24 +83,32 @@ namespace transport int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, h); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, sessionRequest + 64, paddingLength); + SHA256_Final (h, &ctx); } - memcpy (h + 32, pub, 32); + memcpy (h + 32, GetRemotePub (), 32); SHA256 (h, 64, m_H); // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); - MixKey (inputKeyMaterial, derived); + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), GetPriv (), inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::CreateEphemeralKey (uint8_t * pub) + void NTCP2Establisher::KeyDerivationFunction3 (const uint8_t * staticPrivKey) + { + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), staticPrivKey, inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); + } + + void NTCP2Establisher::CreateEphemeralKey () { RAND_bytes (m_EphemeralPrivateKey, 32); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, m_Ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): @@ -133,15 +162,6 @@ namespace transport } - 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_Establisher->m_Y, staticPrivKey, inputKeyMaterial, ctx); - BN_CTX_free (ctx); - m_Establisher->MixKey (inputKeyMaterial, derived); - } - void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; @@ -171,18 +191,14 @@ namespace transport 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]; - m_Establisher->CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (x, 32, m_SessionRequestBuffer); + encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionRequestBuffer); // X encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block - uint8_t key[32]; - m_Establisher->KeyDerivationFunction1 (m_Establisher->m_RemoteStaticKey, m_Establisher->m_EphemeralPrivateKey, x, key); + m_Establisher->KDF1Alice (); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -195,7 +211,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message 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)); @@ -232,15 +248,14 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->m_Y); + decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block - uint8_t key[32]; - m_Establisher->KeyDerivationFunction1 (m_Establisher->m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Establisher->m_Y, key); + m_Establisher->KDF1Bob (); // 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_Establisher->GetH (), 32, key, nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt { if (options[1] == 2) { @@ -281,16 +296,13 @@ namespace transport void NTCP2Session::SendSessionCreated () { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size - // generate key pair (y) - uint8_t y[32]; - m_Establisher->CreateEphemeralKey (y); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (y, 32, m_SessionCreatedBuffer); + encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); + m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -299,7 +311,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->m_H, 32, m_Establisher->m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message @@ -322,14 +334,14 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_Establisher->m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->m_Y); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); + m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->m_K, nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt { uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); @@ -375,16 +387,17 @@ namespace transport int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, m_SessionCreatedBuffer + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, h); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (h, &ctx); } // part1 48 bytes m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); @@ -396,10 +409,9 @@ namespace transport 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 (i2p::context.GetNTCP2StaticPrivateKey (), key); + m_Establisher->KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey ()); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt uint8_t tmp[48]; memcpy (tmp, m_SessionConfirmedBuffer, 48); memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 38b7caf1..cb4cc5d8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -15,20 +15,31 @@ namespace transport { struct NTCP2Establisher { - NTCP2Establisher () { m_Ctx = BN_CTX_new (); }; - ~NTCP2Establisher () { BN_CTX_free (m_Ctx); }; + NTCP2Establisher (); + ~NTCP2Establisher (); + const uint8_t * GetPub () const { return m_EphemeralPublicKey; }; + const uint8_t * GetPriv () const { return m_EphemeralPrivateKey; }; + const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob + uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set + + const uint8_t * GetK () const { return m_K; }; const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetH () const { return m_H; }; + void KDF1Alice (); + void KDF1Bob (); + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - 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 CreateEphemeralKey (uint8_t * pub); + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate + void KeyDerivationFunction3 (const uint8_t * staticPrivKey); // for SessionConfirmed part 2 + void CreateEphemeralKey (); + BN_CTX * m_Ctx; - 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_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; }; @@ -51,7 +62,6 @@ namespace transport private: void CreateNonce (uint64_t seqn, uint8_t * nonce); - void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void KeyDerivationFunctionDataPhase (); // establish From 00c71dc26aa01d116a022b30161bc06a9b4ff417 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Jul 2018 15:56:23 -0400 Subject: [PATCH 10/64] handle SessionConfirmed --- libi2pd/NTCP2.cpp | 114 ++++++++++++++++++++++++++++++++++++++-------- libi2pd/NTCP2.h | 7 ++- 2 files changed, 101 insertions(+), 20 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f0d15926..36ebc0ca 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -98,10 +98,17 @@ namespace transport MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KeyDerivationFunction3 (const uint8_t * staticPrivKey) + void NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), staticPrivKey, inputKeyMaterial, m_Ctx); + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); + } + + void NTCP2Establisher::KDF3Bob () + { + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (m_RemoteStaticKey, m_EphemeralPrivateKey, inputKeyMaterial, m_Ctx); MixKey (inputKeyMaterial, m_K); } @@ -204,7 +211,8 @@ namespace transport memset (options, 0, 16); 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 + m_Establisher->m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options + htobe16buf (options + 4, m_Establisher->m3p2Len); // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved @@ -261,6 +269,7 @@ namespace transport { uint16_t paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; + m_Establisher->m3p2Len = bufbe16toh (options + 4); // TODO: check tsA if (paddingLen > 0) boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), @@ -315,7 +324,8 @@ namespace transport // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 64), boost::asio::transfer_all (), + m_SessionCreatedBufferLen = paddingLen + 64; + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -403,23 +413,22 @@ namespace transport memcpy (h + 32, m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); - size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; - std::vector buf(m3p2Len - 16); + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC 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 ()); - m_Establisher->KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey ()); + m_Establisher->KDF3Alice (); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt uint8_t tmp[48]; memcpy (tmp, m_SessionConfirmedBuffer, 48); memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->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 (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -427,8 +436,13 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice - memcpy (m_SendIV, m_Sipkeysab + 16, 8); //Alice + // Alice + m_SendKey = m_Kab; + m_ReceiveKey = m_Kba; + m_SendSipKey = m_Sipkeysab; + m_ReceiveSipKey = m_Sipkeysba; + memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); + memcpy (m_SendIV, m_Sipkeysab + 16, 8); ReceiveLength (); // TODO: remove @@ -442,8 +456,72 @@ namespace transport void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); - Terminate (); // TODO + (void) bytes_transferred; + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: couldn't send SessionCreated message: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); + m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } + + void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received"); + // update AD + uint8_t h[80]; + memcpy (h, m_Establisher->GetH (), 32); + memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = m_SessionCreatedBufferLen - 64; + if (paddingLength > 0) + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (h, &ctx); + } + // part 1 + uint8_t nonce[12]; + CreateNonce (1, nonce); + i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 48, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false); // decrypt S + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_Establisher->m_H); + + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC + m_Establisher->KDF3Bob (); + memset (nonce, 0, 12); // set nonce to 0 again + i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt + // TODO: process RI and options + // caclulate new h again for KDF data + memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + KeyDerivationFunctionDataPhase (); + // Bob + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + m_SendSipKey = m_Sipkeysba; + m_ReceiveSipKey = m_Sipkeysab; + memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); + memcpy (m_SendIV, m_Sipkeysba + 16, 8); + ReceiveLength (); + } } void NTCP2Session::ClientLogin () @@ -474,7 +552,7 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Sipkeysba); // assume Alice TODO: + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); delete[] m_NextReceivedBuffer; @@ -501,7 +579,7 @@ namespace transport uint8_t nonce[12]; 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: + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) { LogPrint (eLogInfo, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); @@ -540,8 +618,8 @@ namespace transport 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: + i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); + i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_SendSipKey); htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index cb4cc5d8..0576d3c2 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -33,14 +33,15 @@ namespace transport void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate - void KeyDerivationFunction3 (const uint8_t * staticPrivKey); // for SessionConfirmed part 2 + void KDF3Alice (); // for SessionConfirmed part 2 + void KDF3Bob (); void CreateEphemeralKey (); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; - + uint16_t m3p2Len; }; class NTCP2Server; @@ -76,6 +77,7 @@ namespace transport 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); + void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); // data void ReceiveLength (); @@ -98,6 +100,7 @@ namespace transport size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; + const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; uint8_t m_ReceiveIV[8], m_SendIV[8]; From 52f3081a40d94b9944bb82b847be4e08eaf57c23 Mon Sep 17 00:00:00 2001 From: yangfl Date: Tue, 10 Jul 2018 17:39:21 +0800 Subject: [PATCH 11/64] fix typo --- ChangeLog | 4 ++-- build/CMakeLists.txt | 4 ++-- daemon/HTTPServer.cpp | 2 +- debian/i2pd.1 | 2 +- debian/rules | 2 +- docs/Doxyfile | 4 ++-- libi2pd/Destination.cpp | 2 +- libi2pd/NetDb.cpp | 2 +- libi2pd/Reseed.cpp | 2 +- libi2pd/Tunnel.cpp | 2 +- libi2pd_client/AddressBook.cpp | 2 +- libi2pd_client/HTTPProxy.cpp | 2 +- libi2pd_client/I2CP.cpp | 10 +++++----- libi2pd_client/SOCKS.cpp | 4 ++-- .../src/org/kde/necessitas/ministro/IMinistro.aidl | 2 +- .../org/qtproject/qt5/android/bindings/QtActivity.java | 2 +- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54989d44..59a19a3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -68,7 +68,7 @@ - NTCP soft and hard descriptors limits - Support full timestamps in logs ### Changed -- Faster implmentation of GOST R 34.11 hash +- Faster implementation of GOST R 34.11 hash - Reject routers with RSA signtures - Reload config and shudown from Windows GUI - Update tunnels address(destination) without restart @@ -168,7 +168,7 @@ - Initial iOS support ### Changed -- Reduced file descriptiors usage +- Reduced file descriptors usage - Strict reseed checks enabled by default ## Fixed diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 73e76ae0..5876a0f7 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -190,7 +190,7 @@ if (CXX11_SUPPORTED) elseif (CXX0X_SUPPORTED) # gcc 4.6 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" ) elseif (NOT MSVC) - message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?") + message(SEND_ERROR "C++11 standard not seems to be supported by compiler. Too old version?") endif () if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -340,7 +340,7 @@ target_link_libraries(libi2pdclient libi2pd) find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED ) if(NOT DEFINED Boost_INCLUDE_DIRS) - message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") + message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") endif() find_package ( OpenSSL REQUIRED ) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index faf386d8..3fa23dfe 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -862,7 +862,7 @@ namespace http { { /* deny request as it's from a non whitelisted hostname */ res.code = 403; - content = "host missmatch"; + content = "host mismatch"; SendReply(res, content); return; } diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 91e3b60f..9dd44093 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -96,7 +96,7 @@ Router will use system folders like \fI/var/lib/i2pd\fR (\fIdisabled\fR by defau \fB\-\-family=\fR Name of a family, router belongs to. .PP -Switchs, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file. +Switches, 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" diff --git a/debian/rules b/debian/rules index 8e537049..77ecd7b7 100755 --- a/debian/rules +++ b/debian/rules @@ -17,6 +17,6 @@ DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow override_dh_strip: dh_strip --dbg-package=i2pd-dbg -## uncoment this if you have "missing info" problem when building package +## uncomment this if you have "missing info" problem when building package #override_dh_shlibdeps: # dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info diff --git a/docs/Doxyfile b/docs/Doxyfile index c434d2dc..275d668e 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1094,7 +1094,7 @@ HTML_STYLESHEET = # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the @@ -1637,7 +1637,7 @@ EXTRA_PACKAGES = # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, # $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty string, # for the replacement values of the other commands the user is referred to # HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index d3632881..ad7725fc 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -64,7 +64,7 @@ namespace client { it = params->find (I2CP_PARAM_OUTBOUND_NICKNAME); if (it != params->end ()) m_Nickname = it->second; - // otherwise we set deafult nickname in Start when we know local address + // otherwise we set default nickname in Start when we know local address } } } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index b136dfd5..410b71e6 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -734,7 +734,7 @@ namespace data m_Requests.RequestComplete (ident, nullptr); } else - // no more requests for detination possible. delete it + // no more requests for destination possible. delete it m_Requests.RequestComplete (ident, nullptr); } else if(!m_FloodfillBootstrap) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 4a2f8055..eebe9b38 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -300,7 +300,7 @@ namespace data s.read (localFileName, fileNameLength); localFileName[fileNameLength] = 0; s.seekg (extraFieldLength, std::ios::cur); - // take care about data desriptor if presented + // take care about data descriptor if presented if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) { size_t pos = s.tellg (); diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index c7e1b1b4..66620717 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -511,7 +511,7 @@ namespace tunnel HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); break; default: - LogPrint (eLogWarning, "Tunnel: unexpected messsage type ", (int) typeID); + LogPrint (eLogWarning, "Tunnel: unexpected message type ", (int) typeID); } msg = m_Queue.Get (); diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index f29ecee3..bca0e25b 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -377,7 +377,7 @@ namespace client } numAddresses++; auto it = m_Addresses.find (name); - if (it != m_Addresses.end ()) // aleady exists ? + if (it != m_Addresses.end ()) // already exists ? { if (it->second != ident->GetIdentHash ()) // address changed? { diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index ea95a6bd..f0530ac1 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -387,7 +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? + std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); m_ClientRequest.write(m_ClientRequestBuffer); diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index b08fded1..7d7ce558 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -250,7 +250,7 @@ namespace client if (handler) (this->*handler)(m_Payload, m_PayloadLen); else - LogPrint (eLogError, "I2CP: Unknown I2CP messsage ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]); + LogPrint (eLogError, "I2CP: Unknown I2CP message ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]); } void I2CPSession::Terminate () @@ -398,7 +398,7 @@ namespace client } else { - LogPrint (eLogError, "I2CP: create session signature verification falied"); + LogPrint (eLogError, "I2CP: create session signature verification failed"); SendSessionStatusMessage (3); // invalid } } @@ -455,16 +455,16 @@ namespace client LogPrint(eLogError, "I2CP: invalid reconfigure message signature"); } else - LogPrint(eLogError, "I2CP: mapping size missmatch"); + LogPrint(eLogError, "I2CP: mapping size mismatch"); } else - LogPrint(eLogError, "I2CP: destination missmatch"); + LogPrint(eLogError, "I2CP: destination mismatch"); } else LogPrint(eLogError, "I2CP: malfromed destination"); } else - LogPrint(eLogError, "I2CP: session missmatch"); + LogPrint(eLogError, "I2CP: session mismatch"); } else LogPrint(eLogError, "I2CP: short message"); diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index ddf4bbe9..8a67901c 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -84,8 +84,8 @@ namespace proxy SOCKS5_HOST_UNREACH = 4, // Host unreachable SOCKS5_CONN_REFUSED = 5, // Connection refused by the peer SOCKS5_TTL_EXPIRED = 6, // TTL Expired - SOCKS5_CMD_UNSUP = 7, // Command unsuported - SOCKS5_ADDR_UNSUP = 8, // Address type unsuported + SOCKS5_CMD_UNSUP = 7, // Command unsupported + SOCKS5_ADDR_UNSUP = 8, // Address type unsupported SOCKS4_OK = 90, // No error for SOCKS4 SOCKS4_FAIL = 91, // Failed establishing connecting or not allowed SOCKS4_IDENTD_MISSING = 92, // Couldn't connect to the identd server diff --git a/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl b/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl index bbd8116d..e23cb699 100644 --- a/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl +++ b/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl @@ -51,7 +51,7 @@ interface IMinistro * "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations. * "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable * "required.modules" StringArray Required modules by your application -* "application.title" String Application name, used to show more informations to user +* "application.title" String Application name, used to show more information to user * "qt.provider" String Qt libs provider, currently only "necessitas" is supported. * "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 ! * "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)! diff --git a/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java b/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java index 677e8f46..9c607109 100644 --- a/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -97,7 +97,7 @@ import android.view.ActionMode.Callback; public class QtActivity extends Activity { - private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished + private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro installation is finished private static final int MINISTRO_API_LEVEL = 5; // Ministro api level (check IMinistro.aidl file) private static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin private static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0 From 5575b981c85a6bab605cd4ed63b73c1c5eeff76b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Jul 2018 15:59:28 -0400 Subject: [PATCH 12/64] enable NTCP2 as transport --- libi2pd/NTCP2.cpp | 10 ++++++++++ libi2pd/NTCP2.h | 2 ++ libi2pd/Transports.cpp | 24 +++++++++++++++++++++++- libi2pd/Transports.h | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 36ebc0ca..a5e70c24 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -9,6 +9,7 @@ #include "Ed25519.h" #include "Siphash.h" #include "RouterContext.h" +#include "Transports.h" #include "NTCP2.h" namespace i2p @@ -162,6 +163,13 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } + void NTCP2Session::Established () + { + m_IsEstablished = true; + m_Establisher.reset (nullptr); + transports.PeerConnected (shared_from_this ()); + } + void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) { memset (nonce, 0, 4); @@ -443,6 +451,7 @@ namespace transport m_ReceiveSipKey = m_Sipkeysba; memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); memcpy (m_SendIV, m_Sipkeysab + 16, 8); + Established (); ReceiveLength (); // TODO: remove @@ -520,6 +529,7 @@ namespace transport m_ReceiveSipKey = m_Sipkeysab; memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); + Established (); ReceiveLength (); } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 0576d3c2..167b0528 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -62,6 +62,8 @@ namespace transport private: + void Established (); + void CreateNonce (uint64_t seqn, uint8_t * nonce); void KeyDerivationFunctionDataPhase (); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 9914c75e..32f1dc30 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -117,7 +117,8 @@ namespace transport Transports::Transports (): m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), - m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys + m_NTCPServer (nullptr), m_SSUServer (nullptr), m_NTCP2Server (nullptr), + m_DHKeysPairSupplier (5), // 5 pre-generated keys m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), @@ -191,6 +192,13 @@ namespace transport LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy); return; } + // create NTCP2. TODO: move to acceptor + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + if (ntcp2) + { + m_NTCP2Server = new NTCP2Server (); + m_NTCP2Server->Start (); + } // create acceptors auto& addresses = context.GetRouterInfo ().GetAddresses (); @@ -262,6 +270,13 @@ namespace transport m_NTCPServer = nullptr; } + if (m_NTCP2Server) + { + m_NTCP2Server->Stop (); + delete m_NTCP2Server; + m_NTCP2Server = nullptr; + } + m_DHKeysPairSupplier.Stop (); m_IsRunning = false; if (m_Service) m_Service->stop (); @@ -390,6 +405,13 @@ namespace transport { peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); + if (address && address->IsNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + if (address && m_NTCPServer) { #if BOOST_VERSION >= 104900 diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index d4410cb3..47944fff 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -15,6 +15,7 @@ #include "TransportSession.h" #include "NTCPSession.h" #include "SSU.h" +#include "NTCP2.h" #include "RouterInfo.h" #include "I2NPProtocol.h" #include "Identity.h" @@ -154,6 +155,7 @@ namespace transport NTCPServer * m_NTCPServer; SSUServer * m_SSUServer; + NTCP2Server * m_NTCP2Server; mutable std::mutex m_PeersMutex; std::map m_Peers; @@ -179,6 +181,7 @@ namespace transport // for HTTP only const NTCPServer * GetNTCPServer () const { return m_NTCPServer; }; const SSUServer * GetSSUServer () const { return m_SSUServer; }; + const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; }; const decltype(m_Peers)& GetPeers () const { return m_Peers; }; }; From 8c5111e11a25568befa87e2f107d0f7422de79a7 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Jul 2018 15:17:05 -0400 Subject: [PATCH 13/64] handle NTCP2 I2NP messages --- libi2pd/I2NPProtocol.h | 20 ++++++++++++++++++++ libi2pd/NTCP2.cpp | 33 ++++++++++++++++++++++++++++++++- libi2pd/NTCP2.h | 12 ++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index f394d284..01b474be 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -26,6 +26,9 @@ namespace i2p const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1; const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4; + // I2NP NTCP2 header + const size_t I2NP_NTCP2_HEADER_SIZE = I2NP_HEADER_EXPIRATION_OFFSET + 4; + // Tunnel Gateway header const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0; const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4; @@ -194,6 +197,23 @@ namespace tunnel len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); } + // for NTCP2 only + uint8_t * GetNTCP2Header () { return GetPayload () - I2NP_NTCP2_HEADER_SIZE; }; + void FromNTCP2 () + { + const uint8_t * ntcp2 = GetNTCP2Header (); + memcpy (GetHeader () + I2NP_HEADER_TYPEID_OFFSET, ntcp2 + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid + SetExpiration (bufbe32toh (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET)*1000LL); + SetSize (len - offset - I2NP_HEADER_SIZE); + SetChks (0); + } + + void ToNTCP2 () + { + uint8_t * ntcp2 = GetNTCP2Header (); + htobe32buf (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET, bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL); + memcpy (ntcp2 + I2NP_HEADER_TYPEID_OFFSET, GetHeader () + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid + } void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0); void RenewI2NPMessageHeader (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a5e70c24..3a6aa1c6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -167,7 +167,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); - transports.PeerConnected (shared_from_this ()); + // transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) @@ -619,8 +619,39 @@ namespace transport LogPrint (eLogError, "NTCP2: Unexpected block length ", size); break; } + switch (blk) + { + case eNTCP2BlkDateTime: + LogPrint (eLogDebug, "NTCP2: datetime"); + break; + case eNTCP2BlkOptions: + LogPrint (eLogDebug, "NTCP2: options"); + break; + case eNTCP2BlkRouterInfo: + LogPrint (eLogDebug, "NTCP2: RouterInfo"); + break; + case eNTCP2BlkI2NPMessage: + { + LogPrint (eLogDebug, "NTCP2: I2NP"); + auto nextMsg = NewI2NPMessage (size); + nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header + memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); + nextMsg->FromNTCP2 (); + m_Handler.PutNextMessage (nextMsg); + break; + } + case eNTCP2BlkTermination: + LogPrint (eLogDebug, "NTCP2: termination"); + break; + case eNTCP2BlkPadding: + LogPrint (eLogDebug, "NTCP2: padding"); + break; + default: + LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk); + } offset += size; } + m_Handler.Flush (); } void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 167b0528..8ce0ba6d 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -13,6 +13,16 @@ namespace i2p { namespace transport { + enum NTCP2BlockType + { + eNTCP2BlkDateTime = 0, + eNTCP2BlkOptions, // 1 + eNTCP2BlkRouterInfo, // 2 + eNTCP2BlkI2NPMessage, // 3 + eNTCP2BlkTermination, // 4 + eNTCP2BlkPadding = 254 + }; + struct NTCP2Establisher { NTCP2Establisher (); @@ -107,6 +117,8 @@ namespace transport uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; uint8_t m_ReceiveIV[8], m_SendIV[8]; uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; + + i2p::I2NPMessagesHandler m_Handler; }; class NTCP2Server From f38891cace7c63e3d1ba990046b6d828472a1d75 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 11:15:27 -0400 Subject: [PATCH 14/64] fixed build for gcc < 4.8 --- libi2pd/Poly1305.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index 5378d3cb..fdfee5bc 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -133,9 +133,14 @@ namespace crypto struct Poly1305 { - +#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8 + Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0) + { + memset (m_H, 0, sizeof (m_H)); +#else Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) { +#endif m_R.PutKey(key); m_Pad.Put(key + 16); } From b99f8285830112ec92c7ae5d588347ff14918534 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 11:16:40 -0400 Subject: [PATCH 15/64] send I2NP messages through NTCP2 --- libi2pd/I2NPProtocol.h | 1 + libi2pd/NTCP2.cpp | 61 ++++++++++++++++++++++++++++++++++++------ libi2pd/NTCP2.h | 10 ++++++- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 01b474be..deaa2292 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -199,6 +199,7 @@ namespace tunnel } // for NTCP2 only uint8_t * GetNTCP2Header () { return GetPayload () - I2NP_NTCP2_HEADER_SIZE; }; + size_t GetNTCP2Length () const { return GetPayloadLength () + I2NP_NTCP2_HEADER_SIZE; }; void FromNTCP2 () { const uint8_t * ntcp2 = GetNTCP2Header (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 3a6aa1c6..fe277a63 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -125,7 +125,7 @@ namespace transport m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), - m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) + m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); auto addr = in_RemoteRouter->GetNTCPAddress (); @@ -167,7 +167,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); - // transports.PeerConnected (shared_from_this ()); + transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) @@ -455,12 +455,8 @@ namespace transport 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); + //m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); + //SendQueue (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -665,6 +661,7 @@ namespace transport LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message + m_IsSending = true; 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)); } @@ -673,6 +670,54 @@ namespace transport { delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; LogPrint (eLogDebug, "NTCP2: Next frame sent"); + m_IsSending = false; + SendQueue (); + } + + void NTCP2Session::SendQueue () + { + if (!m_SendQueue.empty ()) + { + uint8_t * payload = new uint8_t[NTCP2_UNENCRYPTED_FRAME_MAX_SIZE]; + size_t s = 0; + // add I2NP blocks + while (!m_SendQueue.empty ()) + { + auto msg = m_SendQueue.front (); + size_t len = msg->GetNTCP2Length (); + if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header + { + payload[s] = eNTCP2BlkI2NPMessage; // blk + htobe16buf (payload + s + 1, len); // size + s += 3; + msg->ToNTCP2 (); + memcpy (payload + s, msg->GetNTCP2Header (), len); + s += len; + m_SendQueue.pop_front (); + } + else + break; + } + // add padding block + int paddingSize = (s*NTCP2_MAX_PADDING_RATIO)/100; + if (s + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - s -3; + if (paddingSize) paddingSize = rand () % paddingSize; + payload[s] = eNTCP2BlkPadding; // blk + htobe16buf (payload + s + 1, paddingSize); // size + s += 3; + RAND_bytes (payload + s, paddingSize); + s += paddingSize; + // send + SendNextFrame (payload, s); + delete[] payload; + } + } + + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) + { + for (auto it: msgs) + m_SendQueue.push_back (it); + if (!m_IsSending) SendQueue (); } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 8ce0ba6d..1e04587a 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "RouterInfo.h" @@ -13,6 +14,9 @@ namespace i2p { namespace transport { + + const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; + const int NTCP2_MAX_PADDING_RATIO = 6; // in % enum NTCP2BlockType { eNTCP2BlkDateTime = 0, @@ -68,7 +72,7 @@ namespace transport void ClientLogin (); // Alice void ServerLogin (); // Bob - void SendI2NPMessages (const std::vector >& msgs) {}; // TODO + void SendI2NPMessages (const std::vector >& msgs); private: @@ -100,6 +104,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void SendQueue (); private: @@ -119,6 +124,9 @@ namespace transport uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; i2p::I2NPMessagesHandler m_Handler; + + bool m_IsSending; + std::list > m_SendQueue; }; class NTCP2Server From fc52b2b94098fcdb400f727de7fd101f884c7c1d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 12:56:46 -0400 Subject: [PATCH 16/64] fixed typo --- libi2pd/Poly1305.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index fdfee5bc..9ee46640 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -136,7 +136,7 @@ namespace crypto #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8 Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0) { - memset (m_H, 0, sizeof (m_H)); + memset (&m_H, 0, sizeof (m_H)); #else Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) { From 910a9600bd8f4a04f71de36910cb051637c46a97 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 12:58:29 -0400 Subject: [PATCH 17/64] display NTCP2 session in web console --- daemon/HTTPServer.cpp | 91 +++++++++++++++++++++++++------------------ libi2pd/NTCP2.cpp | 45 ++++++++++++++++++++- libi2pd/NTCP2.h | 14 +++++++ 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 3fa23dfe..c9d6ba40 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -259,6 +259,12 @@ namespace http { s << "Our external address:" << "
\r\n" ; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { + if (address->IsNTCP2 ()) + { + // TODO: show actual address + s << "NTCP2   supported
\r\n"; + continue; + } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: @@ -540,6 +546,46 @@ namespace http { } } + template + static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name) + { + std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; + for (const auto& it: sessions ) + { + if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + // incoming connection doesn't have remote RI + if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << it.second->GetSocket ().remote_endpoint().address ().to_string (); + if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s << "
\r\n" << std::endl; + cnt++; + } + if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; + if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s6 << "
\r\n" << std::endl; + cnt6++; + } + } + if (!tmp_s.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s.str () << "

\r\n
\r\n"; + } + if (!tmp_s6.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s6.str () << "

\r\n
\r\n"; + } + } + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; @@ -548,43 +594,14 @@ namespace http { { auto sessions = ntcpServer->GetNTCPSessions (); if (!sessions.empty ()) - { - std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; - for (const auto& it: sessions ) - { - if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - // incoming connection doesn't have remote RI - if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string (); - if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s << "
\r\n" << std::endl; - cnt++; - } - if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; - if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s6 << "
\r\n" << std::endl; - cnt6++; - } - } - if (!tmp_s.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s.str () << "

\r\n
\r\n"; - } - if (!tmp_s6.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s6.str () << "

\r\n
\r\n"; - } - } + ShowNTCPTransports (s, sessions, "NTCP"); + } + auto ntcp2Server = i2p::transport::transports.GetNTCP2Server (); + if (ntcp2Server) + { + auto sessions = ntcp2Server->GetNTCP2Sessions (); + if (!sessions.empty ()) + ShowNTCPTransports (s, sessions, "NTCP2"); } auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index fe277a63..07ae9b99 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -154,6 +154,9 @@ namespace transport m_IsTerminated = true; m_IsEstablished = false; m_Socket.close (); + transports.PeerDisconnected (shared_from_this ()); + m_Server.RemoveNTCP2Session (shared_from_this ()); + m_SendQueue.clear (); LogPrint (eLogDebug, "NTCP2: session terminated"); } } @@ -741,6 +744,14 @@ namespace transport void NTCP2Server::Stop () { + { + // we have to copy it because Terminate changes m_NTCP2Sessions + auto ntcpSessions = m_NTCP2Sessions; + for (auto& it: ntcpSessions) + it.second->Terminate (); + } + m_NTCP2Sessions.clear (); + if (m_IsRunning) { m_IsRunning = false; @@ -769,12 +780,44 @@ namespace transport } } + bool NTCP2Server::AddNTCP2Session (std::shared_ptr session) + { + if (!session || !session->GetRemoteIdentity ()) return false; + auto& ident = session->GetRemoteIdentity ()->GetIdentHash (); + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + { + LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists"); + session->Terminate(); + return false; + } + m_NTCP2Sessions.insert (std::make_pair (ident, session)); + return true; + } + + void NTCP2Server::RemoveNTCP2Session (std::shared_ptr session) + { + if (session && session->GetRemoteIdentity ()) + m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ()); + } + + std::shared_ptr NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident) + { + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + return it->second; + return nullptr; + } + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); m_Service.post([this, address, port, conn]() { - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + if (this->AddNTCP2Session (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 1e04587a..34d8b943 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "RouterInfo.h" @@ -70,6 +71,9 @@ namespace transport boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + bool IsEstablished () const { return m_IsEstablished; }; + bool IsTerminated () const { return m_IsTerminated; }; + void ClientLogin (); // Alice void ServerLogin (); // Bob void SendI2NPMessages (const std::vector >& msgs); @@ -139,6 +143,10 @@ namespace transport void Start (); void Stop (); + bool AddNTCP2Session (std::shared_ptr session); + void RemoveNTCP2Session (std::shared_ptr session); + std::shared_ptr FindNTCP2Session (const i2p::data::IdentHash& ident); + boost::asio::io_service& GetService () { return m_Service; }; void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); @@ -154,6 +162,12 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::map > m_NTCP2Sessions; + + public: + + // for HTTP/I2PControl + const decltype(m_NTCP2Sessions)& GetNTCP2Sessions () const { return m_NTCP2Sessions; }; }; } } From e0790700cddadbf27f1cbb1945d7c3b341ade00b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 14:19:12 -0400 Subject: [PATCH 18/64] don't connect to unpublished NTCP2 addresses --- libi2pd/NTCP2.cpp | 2 +- libi2pd/RouterInfo.cpp | 3 ++- libi2pd/RouterInfo.h | 2 ++ libi2pd/Transports.cpp | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 07ae9b99..85c7c7ac 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -590,7 +590,7 @@ namespace transport uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) { - LogPrint (eLogInfo, "NTCP2: received message decrypted"); + LogPrint (eLogDebug, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); ReceiveLength (); } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a0b818fb..535c7bd8 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -259,6 +259,7 @@ namespace data if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); + address->ntcp2->isPublished = true; // presence if "i" means "published" } else if (key[0] == 'i') { @@ -292,7 +293,7 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports && !isNtcp2) // we ignore NTCP2 addresses for now. TODO: + if (supportedTransports && (!isNtcp2 || address->IsPublishedNTCP2 ())) // we ignore unpublished NTCP2 only addresses { addresses->push_back(address); m_SupportedTransports |= supportedTransports; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index a12b23e3..07cc3af4 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -94,6 +94,7 @@ namespace data { Tag<32> staticKey; Tag<16> iv; + bool isPublished = false; }; struct Address @@ -124,6 +125,7 @@ namespace data } bool IsNTCP2 () const { return (bool)ntcp2; }; + bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; }; typedef std::list > Addresses; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 32f1dc30..5f2747a6 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -405,7 +405,7 @@ namespace transport { peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); - if (address && address->IsNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + if (address && address->IsPublishedNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled { auto s = std::make_shared (*m_NTCP2Server, peer.router); m_NTCP2Server->Connect (address->host, address->port, s); From d9685e991e6b20d39bda87c1268334896058dd48 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 15:57:18 -0400 Subject: [PATCH 19/64] handle RouterInfo block --- libi2pd/NTCP2.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 85c7c7ac..5bb866cf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -10,6 +10,7 @@ #include "Siphash.h" #include "RouterContext.h" #include "Transports.h" +#include "NetDb.hpp" #include "NTCP2.h" namespace i2p @@ -516,7 +517,21 @@ namespace transport m_Establisher->KDF3Bob (); memset (nonce, 0, 12); // set nonce to 0 again i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt - // TODO: process RI and options + // process RI + if (buf[0] == eNTCP2BlkRouterInfo) + { + auto size = bufbe16toh (buf.data () + 1); + if (size <= buf.size () - 3) + { + // TODO: check flag + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + // TODO: process options + } + else + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + } + else + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); // caclulate new h again for KDF data memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); @@ -585,6 +600,8 @@ namespace transport } else { + m_NumReceivedBytes += bytes_transferred + 2; // + length + i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; @@ -627,8 +644,11 @@ namespace transport LogPrint (eLogDebug, "NTCP2: options"); break; case eNTCP2BlkRouterInfo: - LogPrint (eLogDebug, "NTCP2: RouterInfo"); - break; + { + LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", frame[offset]); + i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); + break; + } case eNTCP2BlkI2NPMessage: { LogPrint (eLogDebug, "NTCP2: I2NP"); @@ -671,6 +691,8 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_NumSentBytes += bytes_transferred; + i2p::transport::transports.UpdateSentBytes (bytes_transferred); delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; LogPrint (eLogDebug, "NTCP2: Next frame sent"); m_IsSending = false; From 66bf4314818facb2485e97a652beb324bf75ee46 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 16:27:43 -0400 Subject: [PATCH 20/64] correct KDF1 calculation --- libi2pd/NTCP2.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 5bb866cf..4421f237 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -48,13 +48,15 @@ namespace transport 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] = + static const uint8_t hh[32] = { 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) memcpy (m_CK, protocolNameHash, 32); // h = SHA256(h || rs) + uint8_t h[64]; + memcpy (h, hh, 32); memcpy (h + 32, rs, 32); SHA256 (h, 64, h); // h = SHA256(h || pub) @@ -645,7 +647,7 @@ namespace transport break; case eNTCP2BlkRouterInfo: { - LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", frame[offset]); + LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); break; } From f6495e59c5ac50a94da2962e0b67accaad23b10c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 09:27:59 -0400 Subject: [PATCH 21/64] better MixHash --- libi2pd/NTCP2.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 4421f237..61d20ed8 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -54,14 +54,17 @@ namespace transport 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) - uint8_t h[64]; - memcpy (h, hh, 32); - memcpy (h + 32, rs, 32); - SHA256 (h, 64, h); + // h = SHA256(hh || rs) + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, rs, 32); + SHA256_Final (m_H, &ctx); // h = SHA256(h || pub) - memcpy (h + 32, pub, 32); - SHA256 (h, 64, m_H); + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (m_H, &ctx); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv @@ -79,22 +82,25 @@ namespace transport } void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) - { - uint8_t h[64]; - memcpy (h, m_H, 32); - memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, h); + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, sessionRequest + 32, 32); // encrypted payload + SHA256_Final (m_H, &ctx); + int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { - SHA256_CTX ctx; SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_H, 32); SHA256_Update (&ctx, sessionRequest + 64, paddingLength); - SHA256_Final (h, &ctx); + SHA256_Final (m_H, &ctx); } - memcpy (h + 32, GetRemotePub (), 32); - SHA256 (h, 64, m_H); + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, GetRemotePub (), 32); + SHA256_Final (m_H, &ctx); // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; From 5001592fb4c45fbffc9fd1c718181ee5ff0ec6c2 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 09:45:24 -0400 Subject: [PATCH 22/64] replace ntcp2 by ntcp2.enabled --- libi2pd/Config.cpp | 7 ++++++- libi2pd/RouterContext.cpp | 4 ++-- libi2pd/Transports.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 1ff55dd6..3233c875 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -59,7 +59,6 @@ namespace config { ("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", 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)") @@ -232,6 +231,11 @@ namespace config { ("exploratory.outbound.quantity", value()->default_value(3), "Exploratory outbound tunnels quantity") ; + options_description ntcp2("NTCP2 Options"); + ntcp2.add_options() + ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ; + m_OptionsDesc .add(general) .add(limits) @@ -249,6 +253,7 @@ namespace config { .add(trust) .add(websocket) .add(exploratory) + .add(ntcp2) ; } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9bd6da9f..48fe400f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -50,7 +50,7 @@ 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 ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname4; i2p::config::GetOption("ifname4", ifname4); @@ -452,7 +452,7 @@ namespace i2p SetReachable (); // we assume reachable until we discover firewall through peer tests // read NTCP2 - bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 5f2747a6..e4a3021b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -193,7 +193,7 @@ namespace transport return; } // create NTCP2. TODO: move to acceptor - bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { m_NTCP2Server = new NTCP2Server (); From 5bedfc1c84a987339d826de7c5e789c5c146ccbb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 12:46:19 -0400 Subject: [PATCH 23/64] post I2NP messages to NTCP2 thread --- libi2pd/NTCP2.cpp | 9 ++++++++- libi2pd/NTCP2.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 61d20ed8..94f0641e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -748,9 +748,16 @@ namespace transport void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { + m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); + } + + void NTCP2Session::PostI2NPMessages (std::vector > msgs) + { + if (m_IsTerminated) return; for (auto it: msgs) m_SendQueue.push_back (it); - if (!m_IsSending) SendQueue (); + if (!m_IsSending) + SendQueue (); } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 34d8b943..c14c6876 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -109,6 +109,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); + void PostI2NPMessages (std::vector > msgs); private: From 460cf6fd20eab9497a5a898b23dd7cc7975cc5b8 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 22:55:41 +0300 Subject: [PATCH 24/64] update windows build script, change makefile.mingw line ending --- Makefile.mingw | 108 +++++++++++++++++++++--------------------- build/build_mingw.cmd | 8 ++-- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Makefile.mingw b/Makefile.mingw index 5dae3723..5f3292d1 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,54 +1,54 @@ -USE_WIN32_APP=yes -CXX = g++ -WINDRES = windres -CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -NEEDED_CXXFLAGS = -std=c++11 -BOOST_SUFFIX = -mt -INCFLAGS = -Idaemon -I. -LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ - -# UPNP Support -ifeq ($(USE_UPNP),yes) - CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB - LDLIBS = -lminiupnpc -endif - -LDLIBS += \ - -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 - -ifeq ($(USE_WIN32_APP), yes) - CXXFLAGS += -DWIN32_APP - LDFLAGS += -mwindows - DAEMON_RC += Win32/Resource.rc - DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) -endif - -# don't change following line to ifeq ($(USE_AESNI),yes) !!! -ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -else - CPU_FLAGS += -msse -endif - -ifeq ($(USE_AVX),1) - CPU_FLAGS += -mavx -endif - -ifeq ($(USE_ASLR),yes) - LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols -endif - -obj/%.o : %.rc - $(WINDRES) -i $< -o $@ +USE_WIN32_APP=yes +CXX = g++ +WINDRES = windres +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +NEEDED_CXXFLAGS = -std=c++11 +BOOST_SUFFIX = -mt +INCFLAGS = -Idaemon -I. +LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ + +# UPNP Support +ifeq ($(USE_UPNP),yes) + CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB + LDLIBS = -lminiupnpc +endif + +LDLIBS += \ + -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 + +ifeq ($(USE_WIN32_APP), yes) + CXXFLAGS += -DWIN32_APP + LDFLAGS += -mwindows + DAEMON_RC += Win32/Resource.rc + DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) +endif + +# don't change following line to ifeq ($(USE_AESNI),yes) !!! +ifeq ($(USE_AESNI),1) + CPU_FLAGS += -maes +else + CPU_FLAGS += -msse +endif + +ifeq ($(USE_AVX),1) + CPU_FLAGS += -mavx +endif + +ifeq ($(USE_ASLR),yes) + LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols +endif + +obj/%.o : %.rc + $(WINDRES) -i $< -o $@ diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index e7811b0b..7f163878 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -62,12 +62,12 @@ exit /b 0 %xSH% "make clean" >> nul echo Building i2pd %tag% for win%bitness%: echo Build AVX+AESNI... -%xSH% "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 echo Build AVX... -%xSH% "make USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 echo Build AESNI... -%xSH% "make USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 echo Build without extensions... -%xSH% "make USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 :EOF \ No newline at end of file From c0a650f28b8d0a2e829c51f95f5b4b32d5e816f9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 23:04:29 +0300 Subject: [PATCH 25/64] update gitignore --- .gitignore | 2 +- android/.gitignore | 9 ++++++--- android_binary_only/.gitignore | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 android_binary_only/.gitignore diff --git a/.gitignore b/.gitignore index 353d839f..c2db70e0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ netDb /i2pd /libi2pd.a /libi2pdclient.a -i2pd.exe +*.exe # Autotools diff --git a/android/.gitignore b/android/.gitignore index 90cd315e..6e42311a 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,12 +1,15 @@ gen tests +bin +libs +log* +obj +.gradle .idea +.externalNativeBuild ant.properties local.properties build.sh -bin -log* -.gradle android.iml build gradle diff --git a/android_binary_only/.gitignore b/android_binary_only/.gitignore new file mode 100644 index 00000000..6e42311a --- /dev/null +++ b/android_binary_only/.gitignore @@ -0,0 +1,18 @@ +gen +tests +bin +libs +log* +obj +.gradle +.idea +.externalNativeBuild +ant.properties +local.properties +build.sh +android.iml +build +gradle +gradlew +gradlew.bat + From cb1e47eb7138d13b3bf48ec4f3a38fa23485caa4 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 23:15:22 +0300 Subject: [PATCH 26/64] use preconfigured configs for android package --- android/assets/i2pd.conf | 79 +++++++++++++++++++++++++++++++- android/assets/subscriptions.txt | 4 +- android/assets/tunnels.conf | 34 +++++++++++++- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf index f4a68aa2..8022b3d9 120000 --- a/android/assets/i2pd.conf +++ b/android/assets/i2pd.conf @@ -1 +1,78 @@ -../../contrib/i2pd.conf \ No newline at end of file +## Configuration file for a typical i2pd user +## See https://i2pd.readthedocs.org/en/latest/configuration.html +## for more options you can use in this file. + +#logfile = /sdcard/i2pd/i2pd.log +loglevel = none + +# host = 1.2.3.4 +# port = 4567 + +ipv4 = true +ipv6 = false + +# ntcp = true +# ntcpproxy = http://127.0.0.1:8118 +# ssu = true + +bandwidth = O +# share = 100 + +# notransit = true +# floodfill = true + +[http] +enabled = true +address = 127.0.0.1 +port = 7070 +# auth = true +# user = i2pd +# pass = changeme + +[httpproxy] +enabled = true +address = 127.0.0.1 +port = 4444 +# keys = http-proxy-keys.dat +# addresshelper = true +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[socksproxy] +enabled = true +address = 127.0.0.1 +port = 4447 +# keys = socks-proxy-keys.dat +# outproxy.enabled = false +# outproxy = 127.0.0.1 +# outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[sam] +enabled = false +# address = 127.0.0.1 +# port = 7656 + +[precomputation] +elgamal = true + +[upnp] +enabled = true +# name = I2Pd + +[reseed] +verify = true +## 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 + +[limits] +transittunnels = 50 diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt index 4fcc444f..8f4afb03 120000 --- a/android/assets/subscriptions.txt +++ b/android/assets/subscriptions.txt @@ -1 +1,3 @@ -../../contrib/subscriptions.txt \ No newline at end of file +http://inr.i2p/export/alive-hosts.txt +http://stats.i2p/cgi-bin/newhosts.txt +http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf index 08767c73..e95fdf2e 120000 --- a/android/assets/tunnels.conf +++ b/android/assets/tunnels.conf @@ -1 +1,33 @@ -../../contrib/tunnels.conf \ No newline at end of file +[IRC-IRC2P] +#type = client +#address = 127.0.0.1 +#port = 6668 +#destination = irc.postman.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[IRC-ILITA] +#type = client +#address = 127.0.0.1 +#port = 6669 +#destination = irc.ilita.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[SMTP] +#type = client +#address = 127.0.0.1 +#port = 7659 +#destination = smtp.postman.i2p +#destinationport = 25 +#keys = smtp-keys.dat + +#[POP3] +#type = client +#address = 127.0.0.1 +#port = 7660 +#destination = pop.postman.i2p +#destinationport = 110 +#keys = pop3-keys.dat + +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ From 2406d57d516354ae83e09b685f5cc004148bf38a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 21 Jul 2018 00:02:54 +0300 Subject: [PATCH 27/64] update android target API to 28, use gradle and ndk parallel building --- android/AndroidManifest.xml | 2 +- android/assets/i2pd.conf | 0 android/assets/subscriptions.txt | 0 android/assets/tunnels.conf | 0 android/build.gradle | 13 +++++++++---- android/gradle.properties | 1 + android/project.properties | 2 +- android/settings.gradle | 1 + 8 files changed, 13 insertions(+), 6 deletions(-) mode change 120000 => 100644 android/assets/i2pd.conf mode change 120000 => 100644 android/assets/subscriptions.txt mode change 120000 => 100644 android/assets/tunnels.conf create mode 100644 android/gradle.properties create mode 100644 android/settings.gradle diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index ca66c17d..705cce4e 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -7,7 +7,7 @@ + android:targetSdkVersion="28" /> diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf deleted file mode 120000 index 8022b3d9..00000000 --- a/android/assets/i2pd.conf +++ /dev/null @@ -1,78 +0,0 @@ -## Configuration file for a typical i2pd user -## See https://i2pd.readthedocs.org/en/latest/configuration.html -## for more options you can use in this file. - -#logfile = /sdcard/i2pd/i2pd.log -loglevel = none - -# host = 1.2.3.4 -# port = 4567 - -ipv4 = true -ipv6 = false - -# ntcp = true -# ntcpproxy = http://127.0.0.1:8118 -# ssu = true - -bandwidth = O -# share = 100 - -# notransit = true -# floodfill = true - -[http] -enabled = true -address = 127.0.0.1 -port = 7070 -# auth = true -# user = i2pd -# pass = changeme - -[httpproxy] -enabled = true -address = 127.0.0.1 -port = 4444 -# keys = http-proxy-keys.dat -# addresshelper = true -# outproxy = http://false.i2p -## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. - -[socksproxy] -enabled = true -address = 127.0.0.1 -port = 4447 -# keys = socks-proxy-keys.dat -# outproxy.enabled = false -# outproxy = 127.0.0.1 -# outproxyport = 9050 -## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. - -[sam] -enabled = false -# address = 127.0.0.1 -# port = 7656 - -[precomputation] -elgamal = true - -[upnp] -enabled = true -# name = I2Pd - -[reseed] -verify = true -## 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 - -[limits] -transittunnels = 50 diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf new file mode 100644 index 00000000..8022b3d9 --- /dev/null +++ b/android/assets/i2pd.conf @@ -0,0 +1,78 @@ +## Configuration file for a typical i2pd user +## See https://i2pd.readthedocs.org/en/latest/configuration.html +## for more options you can use in this file. + +#logfile = /sdcard/i2pd/i2pd.log +loglevel = none + +# host = 1.2.3.4 +# port = 4567 + +ipv4 = true +ipv6 = false + +# ntcp = true +# ntcpproxy = http://127.0.0.1:8118 +# ssu = true + +bandwidth = O +# share = 100 + +# notransit = true +# floodfill = true + +[http] +enabled = true +address = 127.0.0.1 +port = 7070 +# auth = true +# user = i2pd +# pass = changeme + +[httpproxy] +enabled = true +address = 127.0.0.1 +port = 4444 +# keys = http-proxy-keys.dat +# addresshelper = true +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[socksproxy] +enabled = true +address = 127.0.0.1 +port = 4447 +# keys = socks-proxy-keys.dat +# outproxy.enabled = false +# outproxy = 127.0.0.1 +# outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[sam] +enabled = false +# address = 127.0.0.1 +# port = 7656 + +[precomputation] +elgamal = true + +[upnp] +enabled = true +# name = I2Pd + +[reseed] +verify = true +## 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 + +[limits] +transittunnels = 50 diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt deleted file mode 120000 index 8f4afb03..00000000 --- a/android/assets/subscriptions.txt +++ /dev/null @@ -1,3 +0,0 @@ -http://inr.i2p/export/alive-hosts.txt -http://stats.i2p/cgi-bin/newhosts.txt -http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt new file mode 100644 index 00000000..8f4afb03 --- /dev/null +++ b/android/assets/subscriptions.txt @@ -0,0 +1,3 @@ +http://inr.i2p/export/alive-hosts.txt +http://stats.i2p/cgi-bin/newhosts.txt +http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf deleted file mode 120000 index e95fdf2e..00000000 --- a/android/assets/tunnels.conf +++ /dev/null @@ -1,33 +0,0 @@ -[IRC-IRC2P] -#type = client -#address = 127.0.0.1 -#port = 6668 -#destination = irc.postman.i2p -#destinationport = 6667 -#keys = irc-keys.dat - -#[IRC-ILITA] -#type = client -#address = 127.0.0.1 -#port = 6669 -#destination = irc.ilita.i2p -#destinationport = 6667 -#keys = irc-keys.dat - -#[SMTP] -#type = client -#address = 127.0.0.1 -#port = 7659 -#destination = smtp.postman.i2p -#destinationport = 25 -#keys = smtp-keys.dat - -#[POP3] -#type = client -#address = 127.0.0.1 -#port = 7660 -#destination = pop.postman.i2p -#destinationport = 110 -#keys = pop3-keys.dat - -# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf new file mode 100644 index 00000000..e95fdf2e --- /dev/null +++ b/android/assets/tunnels.conf @@ -0,0 +1,33 @@ +[IRC-IRC2P] +#type = client +#address = 127.0.0.1 +#port = 6668 +#destination = irc.postman.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[IRC-ILITA] +#type = client +#address = 127.0.0.1 +#port = 6669 +#destination = irc.ilita.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[SMTP] +#type = client +#address = 127.0.0.1 +#port = 7659 +#destination = smtp.postman.i2p +#destinationport = 25 +#keys = smtp-keys.dat + +#[POP3] +#type = client +#address = 127.0.0.1 +#port = 7660 +#destination = pop.postman.i2p +#destinationport = 110 +#keys = pop3-keys.dat + +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/android/build.gradle b/android/build.gradle index 683f3d27..2a8ad6f4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -18,17 +18,22 @@ repositories { } android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 28 + buildToolsVersion "28.0.1" defaultConfig { applicationId "org.purplei2p.i2pd" - targetSdkVersion 25 + targetSdkVersion 28 minSdkVersion 14 versionCode 1 versionName "2.19.0" ndk { abiFilters 'armeabi-v7a' - //abiFilters 'x86' + abiFilters 'x86' + } + externalNativeBuild { + ndkBuild { + arguments "-j4" + } } } sourceSets { diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..af82e006 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.parallel=true \ No newline at end of file diff --git a/android/project.properties b/android/project.properties index f72b9716..919ca9c3 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-25 +target=android-28 diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..2a620ef9 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "i2pd" From c8f51380e6fb317b32f4bac45063717260d369d9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Jul 2018 16:59:58 -0400 Subject: [PATCH 28/64] publish NTCP2 for new routers --- libi2pd/RouterContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 48fe400f..100d9c44 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -93,10 +93,11 @@ namespace i2p m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); - if (ntcp2) + if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { NewNTCP2Keys (); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + UpdateRouterInfo (); } } From 1a38e925bf3980e459264264f135fbbe47109e1e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 13:51:29 -0400 Subject: [PATCH 29/64] publish NTCP2 address --- libi2pd/RouterContext.cpp | 18 +++++++++++++++++- libi2pd/RouterContext.h | 3 ++- libi2pd/RouterInfo.cpp | 10 +++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 100d9c44..9529a757 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -146,7 +146,7 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->port != port) + if (!address->IsNTCP2 () && address->port != port) { address->port = port; updated = true; @@ -156,6 +156,22 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::PublishNTCP2Address (int port) + { + bool updated = false; + for (auto& address : m_RouterInfo.GetAddresses ()) + { + if (address->IsNTCP2 () && address->port != port) + { + address->port = port; + address->ntcp2->isPublished = true; + updated = true; + } + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ae4aa17e..b840e19a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -76,8 +76,9 @@ namespace i2p 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 UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon + void PublishNTCP2Address (int port); bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 535c7bd8..a38d8fa7 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -456,7 +456,7 @@ namespace data else WriteString ("", s); - if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("host", properties); properties << '='; @@ -538,7 +538,7 @@ namespace data } } - if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("port", properties); properties << '='; @@ -552,7 +552,11 @@ namespace data WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; WriteString ("v", properties); properties << '='; WriteString ("2", properties); properties << ';'; - // TODO: publish "i" + if (address.IsPublishedNTCP2 ()) + { + WriteString ("i", properties); properties << '='; + WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; + } } uint16_t size = htobe16 (properties.str ().size ()); From 998653ea9dfc0fb10099d72a8ee0efe8e7ef7508 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 15:30:51 -0400 Subject: [PATCH 30/64] NTCP2 acceptors --- libi2pd/NTCP2.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 5 +++ 2 files changed, 103 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 94f0641e..e5487a4e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -776,6 +776,48 @@ namespace transport { m_IsRunning = true; m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (const auto& address: addresses) + { + if (!address) continue; + if (address->IsPublishedNTCP2 ()) + { + if (address->host.is_v4()) + { + try + { + m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port))); + } + catch ( std::exception & ex ) + { + LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what()); + continue; + } + + LogPrint (eLogInfo, "NTC2P: Start listening TCP port ", address->port); + auto conn = std::make_shared(*this); + m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); + } + else if (address->host.is_v6() && context.SupportsV6 ()) + { + m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service)); + try + { + m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); + m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); + m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); + m_NTCP2V6Acceptor->listen (); + + LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port); + auto conn = std::make_shared (*this); + m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1)); + } catch ( std::exception & ex ) { + LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); + continue; + } + } + } + } } } @@ -786,6 +828,8 @@ namespace transport auto ntcpSessions = m_NTCP2Sessions; for (auto& it: ntcpSessions) it.second->Terminate (); + for (auto& it: m_PendingIncomingSessions) + it->Terminate (); } m_NTCP2Sessions.clear (); @@ -871,6 +915,60 @@ namespace transport conn->ClientLogin (); } } + + void NTCP2Server::HandleAccept (std::shared_ptr conn, const boost::system::error_code& error) + { + if (!error) + { + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogDebug, "NTCP2: Connected from ", ep); + if (conn) + { + conn->ServerLogin (); + // m_PendingIncomingSessions.push_back (conn); + } + } + else + LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ()); + } + + if (error != boost::asio::error::operation_aborted) + { + conn = std::make_shared (*this); + m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, + conn, std::placeholders::_1)); + } + } + + void NTCP2Server::HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error) + { + if (!error) + { + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogDebug, "NTCP2: Connected from ", ep); + if (conn) + { + conn->ServerLogin (); + // m_PendingIncomingSessions.push_back (conn); + } + } + else + LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ()); + } + + if (error != boost::asio::error::operation_aborted) + { + conn = std::make_shared (*this); + m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, + conn, std::placeholders::_1)); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c14c6876..93a2ac1e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -155,6 +155,9 @@ namespace transport private: void Run (); + void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); + void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); private: @@ -163,7 +166,9 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; std::map > m_NTCP2Sessions; + std::list > m_PendingIncomingSessions; public: From 10e4b5b2a31c09355e643eeb588518d4afd9b77b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 15:44:36 -0400 Subject: [PATCH 31/64] ignore NTCP2 addresses --- libi2pd/NTCPSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index a297ad6a..caddd110 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -819,7 +819,7 @@ namespace transport for (const auto& address: addresses) { if (!address) continue; - if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !address->IsNTCP2 ()) { if (address->host.is_v4()) { From 07e7c2d852cdc076fb271771d0df66d7d4de8ae5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 31 Jul 2018 12:59:38 -0400 Subject: [PATCH 32/64] ntcp2.published and ntcp2.port parameters --- daemon/Daemon.cpp | 11 +++++++++++ libi2pd/Config.cpp | 4 +++- libi2pd/RouterContext.cpp | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index ee56a1c7..5efdc693 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -152,6 +152,17 @@ namespace i2p i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV4 (ipv4); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + if (ntcp2) + { + bool published; i2p::config::GetOption("ntcp2.published", published); + if (published) + { + uint16_t port; i2p::config::GetOption("ntcp2.port", port); + i2p::context.PublishNTCP2Address (port); + } + } + bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetAcceptsTunnels (!transit); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 3233c875..098a7baa 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -233,7 +233,9 @@ namespace config { options_description ntcp2("NTCP2 Options"); ntcp2.add_options() - ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (default: disabled)") + ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)") + ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ; m_OptionsDesc diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9529a757..e8629ad5 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -158,6 +158,8 @@ namespace i2p void RouterContext::PublishNTCP2Address (int port) { + if (!port) + port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { From 0ff9c9da27abb4b04dc032709fe7c6f9bc8022e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 31 Jul 2018 15:41:13 -0400 Subject: [PATCH 33/64] complete Bob side of NTCP2 --- libi2pd/NTCP2.cpp | 135 +++++++++++++++++++++++--------------- libi2pd/NTCP2.h | 10 +-- libi2pd/RouterContext.cpp | 2 +- libi2pd/RouterInfo.cpp | 20 ++++++ libi2pd/RouterInfo.h | 1 + 5 files changed, 109 insertions(+), 59 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e5487a4e..f31044b8 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -41,7 +41,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub) + void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub) { static const uint8_t protocolNameHash[] = { @@ -60,28 +60,28 @@ namespace transport SHA256_Update (&ctx, hh, 32); SHA256_Update (&ctx, rs, 32); SHA256_Final (m_H, &ctx); - // h = SHA256(h || pub) + // h = SHA256(h || epub) SHA256_Init (&ctx); SHA256_Update (&ctx, m_H, 32); - SHA256_Update (&ctx, pub, 32); + SHA256_Update (&ctx, epub, 32); SHA256_Final (m_H, &ctx); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); // rs*priv MixKey (inputKeyMaterial, m_K); } void NTCP2Establisher::KDF1Alice () { - KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ()); + KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), m_RemoteStaticKey, GetPub ()); } void NTCP2Establisher::KDF1Bob () { - KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), GetRemotePub ()); + KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); } - void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) { SHA256_CTX ctx; SHA256_Init (&ctx); @@ -99,7 +99,7 @@ namespace transport } SHA256_Init (&ctx); SHA256_Update (&ctx, m_H, 32); - SHA256_Update (&ctx, GetRemotePub (), 32); + SHA256_Update (&ctx, epub, 32); SHA256_Final (m_H, &ctx); // x25519 between remote pub and priv @@ -108,6 +108,16 @@ namespace transport MixKey (inputKeyMaterial, m_K); } + void NTCP2Establisher::KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen) + { + KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetRemotePub ()); + } + + void NTCP2Establisher::KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen) + { + KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetPub ()); + } + void NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; @@ -137,14 +147,17 @@ namespace transport m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); - auto addr = in_RemoteRouter->GetNTCPAddress (); - if (addr->ntcp2) + if (in_RemoteRouter) // Alice { - memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); + auto addr = in_RemoteRouter->GetNTCP2Address (); + if (addr->ntcp2) + { + memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); + } + else + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } - else - LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } NTCP2Session::~NTCP2Session () @@ -331,7 +344,7 @@ namespace transport encryption.SetIV (m_Establisher->m_IV); encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -342,7 +355,7 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding - RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); + RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // send message m_SessionCreatedBufferLen = paddingLen + 64; boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), @@ -366,7 +379,7 @@ namespace transport decryption.SetIV (m_Establisher->m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Alice (m_SessionRequestBuffer, m_SessionRequestBufferLen); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; @@ -386,7 +399,7 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed "); + LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed "); Terminate (); } } @@ -492,12 +505,12 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ()); Terminate (); } else { - LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received"); + LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received"); // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); @@ -515,44 +528,58 @@ namespace transport // part 1 uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 48, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false); // decrypt S - // part 2 - // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - m_Establisher->KDF3Bob (); - memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt - // process RI - if (buf[0] == eNTCP2BlkRouterInfo) + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S { - auto size = bufbe16toh (buf.data () + 1); - if (size <= buf.size () - 3) + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_Establisher->m_H); + + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC + m_Establisher->KDF3Bob (); + memset (nonce, 0, 12); // set nonce to 0 again + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { - // TODO: check flag - i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag - // TODO: process options - } + // process RI + if (buf[0] == eNTCP2BlkRouterInfo) + { + auto size = bufbe16toh (buf.data () + 1); + if (size <= buf.size () - 3) + { + // TODO: check flag + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + // TODO: process options + } + else + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + } + else + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); + // caclulate new h again for KDF data + memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + KeyDerivationFunctionDataPhase (); + // Bob + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + m_SendSipKey = m_Sipkeysba; + m_ReceiveSipKey = m_Sipkeysab; + memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); + memcpy (m_SendIV, m_Sipkeysba + 16, 8); + Established (); + ReceiveLength (); + } else - LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed "); + Terminate (); + } } else - LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); - // caclulate new h again for KDF data - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - KeyDerivationFunctionDataPhase (); - // Bob - m_SendKey = m_Kba; - m_ReceiveKey = m_Kab; - m_SendSipKey = m_Sipkeysba; - m_ReceiveSipKey = m_Sipkeysab; - memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); - memcpy (m_SendIV, m_Sipkeysba + 16, 8); - Established (); - ReceiveLength (); + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); + Terminate (); + } } } @@ -794,7 +821,7 @@ namespace transport continue; } - LogPrint (eLogInfo, "NTC2P: Start listening TCP port ", address->port); + LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port); auto conn = std::make_shared(*this); m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 93a2ac1e..74043ca1 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -44,12 +44,14 @@ namespace transport void KDF1Alice (); void KDF1Bob (); - - void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate + void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen); + void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen); void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Bob (); + + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + void KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH + void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e8629ad5..93cb741c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -478,7 +478,7 @@ namespace i2p if (n2k) { n2k.seekg (0, std::ios::end); - len = fk.tellg(); + len = n2k.tellg(); n2k.seekg (0, std::ios::beg); if (len == sizeof (NTCP2PrivateKeys)) { diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a38d8fa7..73716989 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -873,6 +873,7 @@ namespace data std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const { + // TODO: make it more gereric using comparator #if (BOOST_VERSION >= 105300) auto addresses = boost::atomic_load (&m_Addresses); #else @@ -889,6 +890,25 @@ namespace data return nullptr; } + std::shared_ptr RouterInfo::GetNTCP2Address (bool v4only) const + { + // TODO: implement through GetAddress +#if (BOOST_VERSION >= 105300) + auto addresses = boost::atomic_load (&m_Addresses); +#else + auto addresses = m_Addresses; +#endif + for (const auto& address : *addresses) + { + if (address->IsPublishedNTCP2 ()) + { + if (!v4only || address->host.is_v4 ()) + return address; + } + } + return nullptr; + } + std::shared_ptr RouterInfo::GetProfile () const { if (!m_Profile) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 07cc3af4..525c6e65 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -142,6 +142,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCPAddress (bool v4only = true) const; + std::shared_ptr GetNTCP2Address (bool v4only = true) const; std::shared_ptr GetSSUAddress (bool v4only = true) const; std::shared_ptr GetSSUV6Address () const; From a8dcfc44f5055ec5925a53f77c118c72c892a25b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 1 Aug 2018 09:43:48 -0400 Subject: [PATCH 34/64] handle termination message --- libi2pd/NTCP2.cpp | 10 ++++++++-- libi2pd/NTCP2.h | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f31044b8..77882b46 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -447,7 +447,7 @@ namespace transport SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - buf[0] = 2; // block + buf[0] = eNTCP2BlkRouterInfo; // 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 ()); @@ -695,7 +695,13 @@ namespace transport break; } case eNTCP2BlkTermination: - LogPrint (eLogDebug, "NTCP2: termination"); + if (size >= 9) + { + LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 9])); + Terminate (); + } + else + LogPrint (eLogWarning, "NTCP2: Unexpected temination block size ", size); break; case eNTCP2BlkPadding: LogPrint (eLogDebug, "NTCP2: padding"); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 74043ca1..b1fe21e6 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -28,6 +28,29 @@ namespace transport eNTCP2BlkPadding = 254 }; + enum NTCP2TerminationReason + { + eNTCP2NormalClose = 0, + eNTCP2TerminationReceived, // 1 + eNTCP2IdleTimeout, // 2 + eNTCP2RouterShutdown, // 3 + eNTCP2DataPhaseAEADFailure, // 4 + eNTCP2IncompatibleOptions, // 5 + eNTCP2IncompatibleSignatureType, // 6 + eNTCP2ClockSkew, // 7 + eNTCP2PaddingViolation, // 8 + eNTCP2AEADFraminError, // 9 + eNTCP2PayloadFromatError, // 10 + eNTCP2Message1Error, // 11 + eNTCP2Message2Error, // 12 + eNTCP2Message3Error, // 13 + eNTCP2IntraFrameReadTimeout, // 14 + eNTCP2RouterInfoSignatureVerificationFail, // 15 + eNTCP2IncorrectSParameter, // 16 + eNTCP2Banned, // 17 + }; + + struct NTCP2Establisher { NTCP2Establisher (); From 2b64cf9126329030f6dc86630c77189b5cd4a484 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 1 Aug 2018 12:28:34 -0400 Subject: [PATCH 35/64] publish i in correct place for NTCP2 --- libi2pd/RouterInfo.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 73716989..14153ba0 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -538,6 +538,13 @@ namespace data } } + if (address.IsPublishedNTCP2 ()) + { + // publish i for NTCP2 + WriteString ("i", properties); properties << '='; + WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; + } + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("port", properties); @@ -552,11 +559,6 @@ namespace data WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; WriteString ("v", properties); properties << '='; WriteString ("2", properties); properties << ';'; - if (address.IsPublishedNTCP2 ()) - { - WriteString ("i", properties); properties << '='; - WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; - } } uint16_t size = htobe16 (properties.str ().size ()); From f96bfa6afa216d78d99c9ebbbf33df0134ac5efb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 12:42:39 -0400 Subject: [PATCH 36/64] send RouterInfo --- libi2pd/NTCP2.cpp | 29 +++++++++++++++++++++++++---- libi2pd/NTCP2.h | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 77882b46..cda25553 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -337,7 +337,9 @@ namespace transport void NTCP2Session::SendSessionCreated () { - m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + auto paddingLen = rand () % (287 - 64); + m_SessionCreatedBufferLen = paddingLen + 64; + m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); @@ -345,7 +347,6 @@ namespace transport encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); - auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen @@ -357,7 +358,6 @@ namespace transport // fill padding RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // send message - m_SessionCreatedBufferLen = paddingLen + 64; boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -437,7 +437,7 @@ namespace transport SHA256_Final (h, &ctx); } // part1 48 bytes - m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size + m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; CreateNonce (1, nonce); i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt @@ -567,6 +567,7 @@ namespace transport memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); Established (); + SendRouterInfo (); ReceiveLength (); } else @@ -598,6 +599,7 @@ namespace transport void NTCP2Session::ReceiveLength () { + if (IsTerminated ()) return; 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)); } @@ -622,6 +624,7 @@ namespace transport void NTCP2Session::Receive () { + if (IsTerminated ()) return; 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)); } @@ -716,6 +719,7 @@ namespace transport void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) { + if (IsTerminated ()) return; uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; m_NextSendBuffer = new uint8_t[len + 16 + 2]; @@ -779,6 +783,23 @@ namespace transport } } + void NTCP2Session::SendRouterInfo () + { + auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); + int paddingSize = (riLen*NTCP2_MAX_PADDING_RATIO)/100; + size_t payloadLen = riLen + paddingSize + 7; // 7 = 2*3 bytes header + 1 byte RI flag + uint8_t * payload = new uint8_t[payloadLen]; + payload[0] = eNTCP2BlkRouterInfo; + htobe16buf (payload + 1, riLen + 1); // size + payload[3] = 0; // flag + memcpy (payload + 4, i2p::context.GetRouterInfo ().GetBuffer (), riLen); + payload[riLen + 4] = eNTCP2BlkPadding; + htobe16buf (payload + riLen + 5, paddingSize); + RAND_bytes (payload + riLen + 7, paddingSize); + SendNextFrame (payload, payloadLen); + delete[] payload; + } + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b1fe21e6..5ac6a280 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -134,6 +134,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); + void SendRouterInfo (); void PostI2NPMessages (std::vector > msgs); private: From 6cf158ac634c8cf477da0a6304fdd316065b6a61 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 13:58:47 -0400 Subject: [PATCH 37/64] check RouterInfo from SessionConfirmed --- libi2pd/NTCP2.cpp | 66 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index cda25553..7a3df9bf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -150,7 +150,7 @@ namespace transport if (in_RemoteRouter) // Alice { auto addr = in_RemoteRouter->GetNTCP2Address (); - if (addr->ntcp2) + if (addr) { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); @@ -469,7 +469,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - // Alice + // Alice data phase keys m_SendKey = m_Kab; m_ReceiveKey = m_Kba; m_SendSipKey = m_Sipkeysab; @@ -540,35 +540,63 @@ namespace transport memset (nonce, 0, 12); // set nonce to 0 again if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { - // process RI - if (buf[0] == eNTCP2BlkRouterInfo) - { - auto size = bufbe16toh (buf.data () + 1); - if (size <= buf.size () - 3) - { - // TODO: check flag - i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag - // TODO: process options - } - else - LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); - } - else - LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); // caclulate new h again for KDF data memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); KeyDerivationFunctionDataPhase (); - // Bob + // Bob data phase keys m_SendKey = m_Kba; m_ReceiveKey = m_Kab; m_SendSipKey = m_Sipkeysba; m_ReceiveSipKey = m_Sipkeysab; memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); + + // process RI + if (buf[0] != eNTCP2BlkRouterInfo) + { + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); + Terminate (); + return; + } + auto size = bufbe16toh (buf.data () + 1); + if (size > buf.size () - 3) + { + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + Terminate (); + return; + } + // TODO: check flag + i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + if (ri.IsUnreachable ()) + { + LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); + Terminate (); + return; + } + auto addr = ri.GetNTCP2Address (); + if (!addr) + { + LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); + Terminate (); + return; + } + if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) + { + LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); + Terminate (); + return; + } + + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // TODO: should insert ri and not parse it twice + // TODO: process options + + // ready to communicate + auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already + SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); Established (); SendRouterInfo (); - ReceiveLength (); + ReceiveLength (); } else { From 0a33c18e367a23dff697e7fc514dea5d4c3c1cc9 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 15:31:15 -0400 Subject: [PATCH 38/64] send termination message --- libi2pd/NTCP2.cpp | 24 +++++++++++++++++++----- libi2pd/NTCP2.h | 4 +++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 7a3df9bf..00d874cc 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -570,8 +570,8 @@ namespace transport i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag if (ri.IsUnreachable ()) { - LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); - Terminate (); + LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); return; } auto addr = ri.GetNTCP2Address (); @@ -583,8 +583,8 @@ namespace transport } if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) { - LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); - Terminate (); + LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2IncorrectSParameter); return; } @@ -728,7 +728,7 @@ namespace transport case eNTCP2BlkTermination: if (size >= 9) { - LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 9])); + LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 8])); Terminate (); } else @@ -828,6 +828,20 @@ namespace transport delete[] payload; } + void NTCP2Session::SendTermination (NTCP2TerminationReason reason) + { + uint8_t payload[12] = { eNTCP2BlkTermination, 0, 9 }; + htobe64buf (payload + 3, m_ReceiveSequenceNumber); + payload[11] = (uint8_t)reason; + SendNextFrame (payload, 12); + } + + void NTCP2Session::SendTerminationAndTerminate (NTCP2TerminationReason reason) + { + SendTermination (reason); + m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go + } + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5ac6a280..c7c53b53 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -40,7 +40,7 @@ namespace transport eNTCP2ClockSkew, // 7 eNTCP2PaddingViolation, // 8 eNTCP2AEADFraminError, // 9 - eNTCP2PayloadFromatError, // 10 + eNTCP2PayloadFormatError, // 10 eNTCP2Message1Error, // 11 eNTCP2Message2Error, // 12 eNTCP2Message3Error, // 13 @@ -135,6 +135,8 @@ namespace transport void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); void SendRouterInfo (); + void SendTermination (NTCP2TerminationReason reason); + void SendTerminationAndTerminate (NTCP2TerminationReason reason); void PostI2NPMessages (std::vector > msgs); private: From 83bbe6a9d91c48f0d4d122a8e2a1b5e764c18d7b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 12:07:09 -0400 Subject: [PATCH 39/64] show NTCP2 address --- daemon/HTTPServer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c9d6ba40..c55714a7 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -259,20 +259,21 @@ namespace http { s << "Our external address:" << "
\r\n" ; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { - if (address->IsNTCP2 ()) + if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) { - // TODO: show actual address s << "NTCP2   supported
\r\n"; continue; } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: - if (address->host.is_v6 ()) - s << "NTCP6  "; - else - s << "NTCP  "; - break; + { + s << "NTCP"; + if (address->IsPublishedNTCP2 ()) s << "2"; + if (address->host.is_v6 ()) s << "6"; + s << "  "; + break; + } case i2p::data::RouterInfo::eTransportSSU: if (address->host.is_v6 ()) s << "SSU6     "; From 50cd321818042775cee6d899664bca63694e93b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 13:10:32 -0400 Subject: [PATCH 40/64] NTCP2 idle timeout --- libi2pd/NTCP2.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++----- libi2pd/NTCP2.h | 16 ++++++++-- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 00d874cc..a6e756fb 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -139,7 +139,7 @@ namespace transport } NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): - TransportSession (in_RemoteRouter, 30), + TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), @@ -183,6 +183,11 @@ namespace transport } } + void NTCP2Session::TerminateByTimeout () + { + SendTerminationAndTerminate (eNTCP2IdleTimeout); + } + void NTCP2Session::Done () { m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); @@ -192,6 +197,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); + SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); transports.PeerConnected (shared_from_this ()); } @@ -666,6 +672,7 @@ namespace transport } else { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumReceivedBytes += bytes_transferred + 2; // + length i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; @@ -679,8 +686,8 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: Received MAC verification failed "); - Terminate (); + LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed "); + SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure); } delete[] decrypted; } @@ -764,6 +771,7 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumSentBytes += bytes_transferred; i2p::transport::transports.UpdateSentBytes (bytes_transferred); delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; @@ -857,7 +865,8 @@ namespace transport } NTCP2Server::NTCP2Server (): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), + m_TerminationTimer (m_Service) { } @@ -914,6 +923,7 @@ namespace transport } } } + ScheduleTermination (); } } @@ -993,13 +1003,27 @@ namespace transport { if (this->AddNTCP2Session (conn)) { - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + auto timer = std::make_shared(m_Service); + auto timeout = NTCP2_CONNECT_TIMEOUT * 5; + conn->SetTerminationTimeout(timeout * 2); + timer->expires_from_now (boost::posix_time::seconds(timeout)); + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); + //i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + conn->Terminate (); + } + }); + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); } }); } - void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn) + void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer) { + timer->cancel (); if (ecode) { LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ()); @@ -1024,7 +1048,7 @@ namespace transport if (conn) { conn->ServerLogin (); - // m_PendingIncomingSessions.push_back (conn); + m_PendingIncomingSessions.push_back (conn); } } else @@ -1051,7 +1075,7 @@ namespace transport if (conn) { conn->ServerLogin (); - // m_PendingIncomingSessions.push_back (conn); + m_PendingIncomingSessions.push_back (conn); } } else @@ -1065,6 +1089,44 @@ namespace transport conn, std::placeholders::_1)); } } + + void NTCP2Server::ScheduleTermination () + { + m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP2_TERMINATION_CHECK_TIMEOUT)); + m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer, + this, std::placeholders::_1)); + } + + void NTCP2Server::HandleTerminationTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + // established + for (auto& it: m_NTCP2Sessions) + if (it.second->IsTerminationTimeoutExpired (ts)) + { + auto session = it.second; + LogPrint (eLogDebug, "NTCP2: No activity for ", session->GetTerminationTimeout (), " seconds"); + session->TerminateByTimeout (); // it doesn't change m_NTCP2Session right a way + } + // pending + for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();) + { + if ((*it)->IsEstablished () || (*it)->IsTerminated ()) + it = m_PendingIncomingSessions.erase (it); // established or terminated + else if ((*it)->IsTerminationTimeoutExpired (ts)) + { + (*it)->Terminate (); + it = m_PendingIncomingSessions.erase (it); // expired + } + else + it++; + } + + ScheduleTermination (); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c7c53b53..e4b2cddd 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -18,6 +18,12 @@ namespace transport const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; const int NTCP2_MAX_PADDING_RATIO = 6; // in % + + const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds + const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds + const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes + const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds + enum NTCP2BlockType { eNTCP2BlkDateTime = 0, @@ -39,7 +45,7 @@ namespace transport eNTCP2IncompatibleSignatureType, // 6 eNTCP2ClockSkew, // 7 eNTCP2PaddingViolation, // 8 - eNTCP2AEADFraminError, // 9 + eNTCP2AEADFramingError, // 9 eNTCP2PayloadFormatError, // 10 eNTCP2Message1Error, // 11 eNTCP2Message2Error, // 12 @@ -92,6 +98,7 @@ namespace transport NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCP2Session (); void Terminate (); + void TerminateByTimeout (); void Done (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -186,7 +193,11 @@ namespace transport void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); - void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); + + // timer + void ScheduleTermination (); + void HandleTerminationTimer (const boost::system::error_code& ecode); private: @@ -194,6 +205,7 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + boost::asio::deadline_timer m_TerminationTimer; std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; From 4cf79088f944956862ee5fde0160091879aed673 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 13:19:35 -0400 Subject: [PATCH 41/64] NTCP2 idle timeout --- libi2pd/NTCP2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a6e756fb..35100ef6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -942,6 +942,7 @@ namespace transport if (m_IsRunning) { m_IsRunning = false; + m_TerminationTimer.cancel (); m_Service.stop (); if (m_Thread) { From f7415c8a8fa9942f48ee089c5035dd2155081d18 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 14:49:28 -0400 Subject: [PATCH 42/64] enable/disable NTCP2 address --- daemon/Daemon.cpp | 4 +++- libi2pd/RouterContext.cpp | 41 ++++++++++++++++++++++++++++++++------- libi2pd/RouterContext.h | 3 ++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 5efdc693..1302ebe8 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -159,8 +159,10 @@ namespace i2p if (published) { uint16_t port; i2p::config::GetOption("ntcp2.port", port); - i2p::context.PublishNTCP2Address (port); + i2p::context.PublishNTCP2Address (port, true); // publish } + else + i2p::context.PublishNTCP2Address (port, false); // unpublish } bool transit; i2p::config::GetOption("notransit", transit); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 93cb741c..d34acc57 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -96,8 +96,7 @@ namespace i2p if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { NewNTCP2Keys (); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - UpdateRouterInfo (); + UpdateNTCP2Address (true); } } @@ -156,17 +155,17 @@ namespace i2p UpdateRouterInfo (); } - void RouterContext::PublishNTCP2Address (int port) + void RouterContext::PublishNTCP2Address (int port, bool publish) { if (!port) port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && address->port != port) + if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish)) { address->port = port; - address->ntcp2->isPublished = true; + address->ntcp2->isPublished = publish; updated = true; } } @@ -174,6 +173,32 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::UpdateNTCP2Address (bool enable) + { + auto& addresses = m_RouterInfo.GetAddresses (); + bool found = false, updated = false; + for (auto it = addresses.begin (); it != addresses.end (); ++it) + { + if ((*it)->IsNTCP2 ()) + { + found = true; + if (!enable) + { + addresses.erase (it); + updated= true; + } + break; + } + } + if (enable && !found) + { + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + updated = true; + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; @@ -310,7 +335,7 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (auto it = addresses.begin (); it != addresses.end (); ++it) { - if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && + if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () && (*it)->host.is_v4 ()) { addresses.erase (it); @@ -490,9 +515,11 @@ namespace i2p if (!m_NTCP2Keys) { NewNTCP2Keys (); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + UpdateNTCP2Address (true); // enable NTCP2 } } + else + UpdateNTCP2Address (false); // disable NTCP2 return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index b840e19a..f1a62c5a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -78,7 +78,8 @@ namespace i2p void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon - void PublishNTCP2Address (int port); + void PublishNTCP2Address (int port, bool publish = true); + void UpdateNTCP2Address (bool enable); bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; From 26d0177c0113b60795dd783dc0fc733f4ab29e7f Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 20:28:29 -0400 Subject: [PATCH 43/64] always make NTCP address first --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 14153ba0..2151ef3d 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -672,7 +672,7 @@ namespace data for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; - m_Addresses->push_back(std::move(addr)); + m_Addresses->push_front(std::move(addr)); // always make NTCP first } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) From 09c6faf9232935bdf9adb8e0e5974ca6a0d71e2b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 21:16:35 -0400 Subject: [PATCH 44/64] don't overwrite NTCP2 keys --- libi2pd/RouterContext.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d34acc57..a1ce6838 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -95,7 +95,7 @@ namespace i2p if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { - NewNTCP2Keys (); + if (!m_NTCP2Keys) NewNTCP2Keys (); UpdateNTCP2Address (true); } } @@ -473,7 +473,21 @@ namespace i2p m_Keys.FromBuffer (buf, len); delete[] buf; } - + // read NTCP2 keys if available + std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); + if (n2k) + { + n2k.seekg (0, std::ios::end); + len = n2k.tellg(); + n2k.seekg (0, std::ios::beg); + if (len == sizeof (NTCP2PrivateKeys)) + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + n2k.close (); + } + // read RouterInfo m_RouterInfo.SetRouterIdentity (GetIdentity ()); i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); if (!routerInfo.IsUnreachable ()) // router.info looks good @@ -499,24 +513,8 @@ namespace i2p bool ntcp2; i2p::config::GetOption("ntcp2.enabled", 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 = n2k.tellg(); - n2k.seekg (0, std::ios::beg); - if (len == sizeof (NTCP2PrivateKeys)) - { - m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); - n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); - } - n2k.close (); - } - if (!m_NTCP2Keys) - { - NewNTCP2Keys (); - UpdateNTCP2Address (true); // enable NTCP2 - } + if (!m_NTCP2Keys) NewNTCP2Keys (); + UpdateNTCP2Address (true); // enable NTCP2 } else UpdateNTCP2Address (false); // disable NTCP2 From 41b9f19b019fb8223975d4b6afe0b54ac7b19c25 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 4 Aug 2018 08:47:58 -0400 Subject: [PATCH 45/64] get unpublished NTCP2 address --- libi2pd/NTCP2.cpp | 4 ++-- libi2pd/RouterInfo.cpp | 50 ++++++++++++++++++++---------------------- libi2pd/RouterInfo.h | 5 +++-- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 35100ef6..0d66f08f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -149,7 +149,7 @@ namespace transport m_Establisher.reset (new NTCP2Establisher); if (in_RemoteRouter) // Alice { - auto addr = in_RemoteRouter->GetNTCP2Address (); + auto addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); @@ -580,7 +580,7 @@ namespace transport SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); return; } - auto addr = ri.GetNTCP2Address (); + auto addr = ri.GetNTCP2Address (false); // any NTCP2 address if (!addr) { LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2151ef3d..21f7132f 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -860,20 +860,33 @@ namespace data std::shared_ptr RouterInfo::GetNTCPAddress (bool v4only) const { - return GetAddress (eTransportNTCP, v4only); + return GetAddress ( + [v4only](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportNTCP) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetSSUAddress (bool v4only) const { - return GetAddress (eTransportSSU, v4only); + return GetAddress ( + [v4only](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetSSUV6Address () const { - return GetAddress (eTransportSSU, false, true); + return GetAddress ( + [](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && address->host.is_v6 (); + }); } - std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const + template + std::shared_ptr RouterInfo::GetAddress (Filter filter) const { // TODO: make it more gereric using comparator #if (BOOST_VERSION >= 105300) @@ -882,33 +895,18 @@ namespace data auto addresses = m_Addresses; #endif for (const auto& address : *addresses) - { - if (address->transportStyle == s) - { - if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ())) - return address; - } - } + if (filter (address)) return address; + return nullptr; } - std::shared_ptr RouterInfo::GetNTCP2Address (bool v4only) const + std::shared_ptr RouterInfo::GetNTCP2Address (bool publishedOnly, bool v4only) const { - // TODO: implement through GetAddress -#if (BOOST_VERSION >= 105300) - auto addresses = boost::atomic_load (&m_Addresses); -#else - auto addresses = m_Addresses; -#endif - for (const auto& address : *addresses) - { - if (address->IsPublishedNTCP2 ()) + return GetAddress ( + [publishedOnly, v4only](std::shared_ptr address)->bool { - if (!v4only || address->host.is_v4 ()) - return address; - } - } - return nullptr; + return address->IsNTCP2 () && (!publishedOnly || address->IsPublishedNTCP2 ()) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetProfile () const diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 525c6e65..f95659d7 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -142,7 +142,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCPAddress (bool v4only = true) const; - std::shared_ptr GetNTCP2Address (bool v4only = true) const; + std::shared_ptr GetNTCP2Address (bool publishedOnly, bool v4only = true) const; std::shared_ptr GetSSUAddress (bool v4only = true) const; std::shared_ptr GetSSUV6Address () const; @@ -216,7 +216,8 @@ namespace data size_t ReadString (char* str, size_t len, std::istream& s) const; void WriteString (const std::string& str, std::ostream& s) const; void ExtractCaps (const char * value); - std::shared_ptr GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; + template + std::shared_ptr GetAddress (Filter filter) const; void UpdateCapsProperty (); private: From f407022fe6c4f5373fea360d7c4672a2cdbbc9d8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 4 Aug 2018 13:48:09 -0400 Subject: [PATCH 46/64] connect to NTCP2 address if presented --- libi2pd/Transports.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index e4a3021b..922625d2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -404,14 +404,19 @@ namespace transport if (!peer.numAttempts) // NTCP { peer.numAttempts++; - auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); - if (address && address->IsPublishedNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + if (m_NTCP2Server) // we support NTCP2 { - auto s = std::make_shared (*m_NTCP2Server, peer.router); - m_NTCP2Server->Connect (address->host, address->port, s); - return true; - } - + // NTCP2 have priority over NTCP + auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + } + // otherwise NTCP1 + auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { #if BOOST_VERSION >= 104900 From 2b61f9a7312fe7c462f9d69741abf588fc1bfce4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 7 Aug 2018 10:35:25 -0400 Subject: [PATCH 47/64] fixed #1217. verify decryption result --- libi2pd/Crypto.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 24ce9c72..0a9093a2 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,7 +1081,8 @@ namespace crypto 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_DecryptUpdate(ctx, buf, &outlen, msg, msgLen); + ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0; } EVP_CIPHER_CTX_free (ctx); From f7728aa1f614ca098c8099073c3587e7c0661981 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Aug 2018 16:23:44 -0400 Subject: [PATCH 48/64] reuse NTCP2 frame buffers --- libi2pd/NTCP2.cpp | 17 +++++++++++------ libi2pd/NTCP2.h | 8 ++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0d66f08f..3dda72e2 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -143,7 +143,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_NextSendBuffer (nullptr), + m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); @@ -647,11 +647,15 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); + uint16_t oldLen = m_NextReceivedLen; 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]; + if (m_NextReceivedLen > oldLen) + { + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + } Receive (); } } @@ -784,7 +788,8 @@ namespace transport { if (!m_SendQueue.empty ()) { - uint8_t * payload = new uint8_t[NTCP2_UNENCRYPTED_FRAME_MAX_SIZE]; + auto buf = m_Server.NewNTCP2FrameBuffer (); + uint8_t * payload = buf->data (); size_t s = 0; // add I2NP blocks while (!m_SendQueue.empty ()) @@ -815,7 +820,7 @@ namespace transport s += paddingSize; // send SendNextFrame (payload, s); - delete[] payload; + m_Server.DeleteNTCP2FrameBuffer (buf); } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e4b2cddd..f63479ed 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -6,8 +6,10 @@ #include #include #include +#include #include #include +#include "util.h" #include "RouterInfo.h" #include "TransportSession.h" @@ -57,6 +59,7 @@ namespace transport }; + typedef std::array NTCP2FrameBuffer; struct NTCP2Establisher { NTCP2Establisher (); @@ -187,6 +190,9 @@ namespace transport void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); + NTCP2FrameBuffer * NewNTCP2FrameBuffer () { return m_NTCP2FrameBuffersPool.Acquire(); } + void DeleteNTCP2FrameBuffer (NTCP2FrameBuffer * buf) { return m_NTCP2FrameBuffersPool.Release(buf); } + private: void Run (); @@ -210,6 +216,8 @@ namespace transport std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; + i2p::util::MemoryPool m_NTCP2FrameBuffersPool; + public: // for HTTP/I2PControl From 5cc84133e3f1a493e5ae01c9834eedd87e6f5095 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Aug 2018 17:38:21 -0400 Subject: [PATCH 49/64] fixed incorrect lenght --- libi2pd/NTCP2.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 3dda72e2..8b75353d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -648,14 +648,10 @@ namespace transport else { i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); - uint16_t oldLen = m_NextReceivedLen; m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - if (m_NextReceivedLen > oldLen) - { - delete[] m_NextReceivedBuffer; - m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; - } + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; Receive (); } } From d8c6dede7e4983bced0c430a552a4a4878b69f79 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 12:53:36 -0400 Subject: [PATCH 50/64] moved NTCP2 handshake buffers to establisher --- libi2pd/NTCP2.cpp | 146 ++++++++++++++++++++++++++-------------------- libi2pd/NTCP2.h | 12 ++-- 2 files changed, 91 insertions(+), 67 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8b75353d..0e3f263f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -17,7 +17,8 @@ namespace i2p { namespace transport { - NTCP2Establisher::NTCP2Establisher () + NTCP2Establisher::NTCP2Establisher (): + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) { m_Ctx = BN_CTX_new (); CreateEphemeralKey (); @@ -26,6 +27,9 @@ namespace transport NTCP2Establisher::~NTCP2Establisher () { BN_CTX_free (m_Ctx); + delete[] m_SessionRequestBuffer; + delete[] m_SessionCreatedBuffer; + delete[] m_SessionConfirmedBuffer; } void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) @@ -108,14 +112,14 @@ namespace transport MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KDF2Alice () { - KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetRemotePub ()); + KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); } - void NTCP2Establisher::KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KDF2Bob () { - KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetPub ()); + KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); } void NTCP2Establisher::KDF3Alice () @@ -138,11 +142,24 @@ namespace transport i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } + void NTCP2Establisher::CreateSessionRequestBuffer (size_t paddingLen) + { + m_SessionRequestBufferLen = paddingLen + 64; + m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; + RAND_bytes (m_SessionRequestBuffer + 64, paddingLen); + } + + void NTCP2Establisher::CreateSessionCreatedBuffer (size_t paddingLen) + { + m_SessionCreatedBufferLen = paddingLen + 64; + m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; + RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { @@ -162,9 +179,6 @@ namespace transport NTCP2Session::~NTCP2Session () { - delete[] m_SessionRequestBuffer; - delete[] m_SessionCreatedBuffer; - delete[] m_SessionConfirmedBuffer; delete[] m_NextReceivedBuffer; delete[] m_NextSendBuffer; } @@ -234,14 +248,12 @@ namespace transport { // create buffer and fill padding auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_SessionRequestBufferLen = paddingLength + 64; - m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; - RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + m_Establisher->CreateSessionRequestBuffer (paddingLength); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionRequestBuffer); // X + encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionRequestBuffer); // X encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block m_Establisher->KDF1Alice (); @@ -258,9 +270,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::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionRequestBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -274,9 +286,9 @@ namespace transport } else { - m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + m_Establisher->m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // 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 (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -295,24 +307,34 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); + decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block m_Establisher->KDF1Bob (); // 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_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt { if (options[1] == 2) { uint16_t paddingLen = bufbe16toh (options + 2); - m_SessionRequestBufferLen = paddingLen + 64; + m_Establisher->m_SessionRequestBufferLen = paddingLen + 64; m_Establisher->m3p2Len = bufbe16toh (options + 4); // 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)); + { + if (paddingLen <= 287 - 64) // session request is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); + Terminate (); + } + } else SendSessionCreated (); } @@ -344,15 +366,14 @@ namespace transport void NTCP2Session::SendSessionCreated () { auto paddingLen = rand () % (287 - 64); - m_SessionCreatedBufferLen = paddingLen + 64; - m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; + m_Establisher->CreateSessionCreatedBuffer (paddingLen); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y + encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Bob (); uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen @@ -360,11 +381,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::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt - // fill padding - RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionCreatedBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -378,26 +397,26 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - m_SessionCreatedBufferLen = 64; + m_Establisher->m_SessionCreatedBufferLen = 64; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_Establisher->m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); + decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KDF2Alice (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Alice (); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt { 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 + 64, paddingLen), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else @@ -420,7 +439,7 @@ namespace transport } else { - m_SessionCreatedBufferLen += bytes_transferred; + m_Establisher->m_SessionCreatedBufferLen += bytes_transferred; SendSessionConfirmed (); } } @@ -431,25 +450,25 @@ namespace transport // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); - int paddingLength = m_SessionCreatedBufferLen - 64; + int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { SHA256_CTX ctx; SHA256_Init (&ctx); SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); SHA256_Final (h, &ctx); } // part1 48 bytes - m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); + memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC @@ -459,15 +478,15 @@ namespace transport memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); m_Establisher->KDF3Alice (); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt uint8_t tmp[48]; - memcpy (tmp, m_SessionConfirmedBuffer, 48); - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - memcpy (m_SessionConfirmedBuffer, tmp, 48); + memcpy (tmp, m_Establisher->m_SessionConfirmedBuffer, 48); + memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + memcpy (m_Establisher->m_SessionConfirmedBuffer, tmp, 48); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -501,8 +520,8 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); - m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -511,44 +530,44 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ()); Terminate (); } else { - LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received"); + LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); - int paddingLength = m_SessionCreatedBufferLen - 64; + int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { SHA256_CTX ctx; SHA256_Init (&ctx); SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); SHA256_Final (h, &ctx); } // part 1 uint8_t nonce[12]; CreateNonce (1, nonce); - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S { // part 2 // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); + memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC m_Establisher->KDF3Bob (); memset (nonce, 0, 12); // set nonce to 0 again - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { // caclulate new h again for KDF data - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); KeyDerivationFunctionDataPhase (); // Bob data phase keys m_SendKey = m_Kba; @@ -625,8 +644,8 @@ namespace transport 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 (), + m_Establisher->m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -650,7 +669,7 @@ namespace transport i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - delete[] m_NextReceivedBuffer; + if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; Receive (); } @@ -682,6 +701,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); + delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore ReceiveLength (); } else diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index f63479ed..00f4275e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -76,8 +76,8 @@ namespace transport void KDF1Alice (); void KDF1Bob (); - void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen); - void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen); + void KDF2Alice (); + void KDF2Bob (); void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Bob (); @@ -86,11 +86,17 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); + void CreateSessionRequestBuffer (size_t paddingLength); + void CreateSessionCreatedBuffer (size_t paddingLength); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; uint16_t m3p2Len; + + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; + size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; + }; class NTCP2Server; @@ -156,8 +162,6 @@ namespace transport bool m_IsEstablished, m_IsTerminated; std::unique_ptr m_Establisher; - 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_Sipkeysab[33], m_Sipkeysba[32]; const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; From 88e87d589bdd5835a928a48033b2a2d1a3ff3473 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 14:20:10 -0400 Subject: [PATCH 51/64] add incoming NTCP2 session to the sessions list --- libi2pd/NTCP2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0e3f263f..6f524920 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -619,6 +619,7 @@ namespace transport // ready to communicate auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); + m_Server.AddNTCP2Session (shared_from_this ()); Established (); SendRouterInfo (); ReceiveLength (); From f7e4afc2827d285b66fb570f82f411bd6f9b94bb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 15:47:02 -0400 Subject: [PATCH 52/64] use same buffer for input and output for AEAD/Chacha20/Poly1305 --- libi2pd/Crypto.cpp | 18 ++++++++++++++---- libi2pd/NTCP2.cpp | 6 ++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 0a9093a2..3f214b0e 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1018,9 +1018,6 @@ namespace crypto 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 if (!ad) adLen = 0; @@ -1038,7 +1035,20 @@ namespace crypto memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } } - memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data + // encrypt/decrypt data and add to hash + memcpy (buf, msg, msgLen); + if (encrypt) + { + chacha20 (buf, msgLen, nonce, key, 1); // encrypt + memcpy (polyMsg.data () + offset, buf, msgLen); // after encryption + } + else + { + memcpy (polyMsg.data () + offset, buf, msgLen); // before decryption + chacha20 (buf, msgLen, nonce, key, 1); // decrypt + } + offset += msgLen; // encrypted data + auto rem = msgLen & 0x0F; // %16 if (rem) { diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6f524920..91b897f5 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -697,11 +697,10 @@ namespace transport i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; 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_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) { LogPrint (eLogDebug, "NTCP2: received message decrypted"); - ProcessNextFrame (decrypted, m_NextReceivedLen-16); + ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore ReceiveLength (); } @@ -710,7 +709,6 @@ namespace transport LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed "); SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure); } - delete[] decrypted; } } From d320a89590c704ddd4f63d7d52193bf23e0c6dee Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 16:32:43 -0400 Subject: [PATCH 53/64] don't copy buffer to ifself --- libi2pd/Crypto.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 3f214b0e..7a947d34 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1036,7 +1036,8 @@ namespace crypto } } // encrypt/decrypt data and add to hash - memcpy (buf, msg, msgLen); + if (buf != msg) + memcpy (buf, msg, msgLen); if (encrypt) { chacha20 (buf, msgLen, nonce, key, 1); // encrypt From 5b83d4bef81000d75d9081296adeb9677134e8e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 10:53:34 -0400 Subject: [PATCH 54/64] move handshake messages creation to NTCP2Establisher --- libi2pd/NTCP2.cpp | 183 +++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 7 +- 2 files changed, 104 insertions(+), 86 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 91b897f5..b54d6cd7 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -142,20 +142,108 @@ namespace transport i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } - void NTCP2Establisher::CreateSessionRequestBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionRequestMessage () { - m_SessionRequestBufferLen = paddingLen + 64; + // create buffer and fill padding + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + m_SessionRequestBufferLen = paddingLength + 64; m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; - RAND_bytes (m_SessionRequestBuffer + 64, paddingLen); + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // encrypt X + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (m_RemoteIdentHash); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X + encryption.GetIV (m_IV); // save IV for SessionCreated + // encryption key for next block + KDF1Alice (); + // fill options + uint8_t options[32]; // actual options size is 16 bytes + memset (options, 0, 16); + options[1] = 2; // ver + htobe16buf (options + 2, paddingLength); // padLen + m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options + htobe16buf (options + 4, m3p2Len); + // 2 bytes reserved + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA + // 4 bytes reserved + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt } - void NTCP2Establisher::CreateSessionCreatedBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionCreatedMessage () { + auto paddingLen = rand () % (287 - 64); m_SessionCreatedBufferLen = paddingLen + 64; m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + // encrypt Y + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (i2p::context.GetIdentHash ()); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y + // encryption key for next block (m_K) + KDF2Bob (); + uint8_t options[16]; + memset (options, 0, 16); + htobe16buf (options + 2, paddingLen); // padLen + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + } + void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) + { + // update AD + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256_Final (m_H, &ctx); + + int paddingLength = m_SessionCreatedBufferLen - 64; + if (paddingLength > 0) + { + SHA256_CTX ctx1; + SHA256_Init (&ctx1); + SHA256_Update (&ctx1, m_H, 32); + SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (m_H, &ctx1); + } + // part1 48 bytes + m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + } + + void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) + { + // part 2 + // update AD again + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48); + SHA256_Final (m_H, &ctx); + // fill and encrypt + uint8_t * buf = m_SessionConfirmedBuffer + 48; + buf[0] = eNTCP2BlkRouterInfo; // block + htobe16buf (buf + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI + buf[3] = 0; // flag + memcpy (buf + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); + KDF3Alice (); + i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, m_K, nonce, buf, m3p2Len, true); // encrypt + // update h again + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, m3p2Len); + SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), @@ -166,6 +254,7 @@ namespace transport m_Establisher.reset (new NTCP2Establisher); if (in_RemoteRouter) // Alice { + m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash (); auto addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { @@ -246,31 +335,7 @@ namespace transport void NTCP2Session::SendSessionRequest () { - // create buffer and fill padding - auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_Establisher->CreateSessionRequestBuffer (paddingLength); - // encrypt X - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionRequestBuffer); // X - encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated - // encryption key for next block - m_Establisher->KDF1Alice (); - // fill options - uint8_t options[32]; // actual options size is 16 bytes - memset (options, 0, 16); - options[1] = 2; // ver - htobe16buf (options + 2, paddingLength); // padLen - m_Establisher->m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options - htobe16buf (options + 4, m_Establisher->m3p2Len); - // 2 bytes reserved - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA - // 4 bytes reserved - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionRequestBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionRequestMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -365,23 +430,7 @@ namespace transport void NTCP2Session::SendSessionCreated () { - auto paddingLen = rand () % (287 - 64); - m_Establisher->CreateSessionCreatedBuffer (paddingLen); - // encrypt Y - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionCreatedBuffer); // Y - // encryption key for next block (m_K) - m_Establisher->KDF2Bob (); - uint8_t options[16]; - memset (options, 0, 16); - htobe16buf (options + 2, paddingLen); // padLen - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionCreatedBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionCreatedMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -444,47 +493,13 @@ namespace transport } } - void NTCP2Session::SendSessionConfirmed () { - // update AD - uint8_t h[80]; - memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload - SHA256 (h, 64, h); - int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; - if (paddingLength > 0) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); - SHA256_Final (h, &ctx); - } - // part1 48 bytes - m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; - CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer, 48, true); // encrypt - // part 2 - // update AD again - memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - buf[0] = eNTCP2BlkRouterInfo; // 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 ()); - m_Establisher->KDF3Alice (); - memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt - uint8_t tmp[48]; - memcpy (tmp, m_Establisher->m_SessionConfirmedBuffer, 48); - memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - memcpy (m_Establisher->m_SessionConfirmedBuffer, tmp, 48); - + CreateNonce (1, nonce); // set nonce to 1 + m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); + memset (nonce, 0, 12); // set nonce back to 0 + m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 00f4275e..b5540b43 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -86,12 +86,15 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); - void CreateSessionRequestBuffer (size_t paddingLength); - void CreateSessionCreatedBuffer (size_t paddingLength); + void CreateSessionRequestMessage (); + void CreateSessionCreatedMessage (); + void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); + void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; + i2p::data::IdentHash m_RemoteIdentHash; uint16_t m3p2Len; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; From 9884a4336f35e3c71c075d1c1d706b17585c8165 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 13:42:59 -0400 Subject: [PATCH 55/64] don't connect to NTCP2 only address using NTCP --- libi2pd/RouterContext.cpp | 11 +++++------ libi2pd/RouterInfo.cpp | 10 ++++++---- libi2pd/RouterInfo.h | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a1ce6838..ee895e32 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -84,6 +84,11 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } + if (ntcp2) + { + if (!m_NTCP2Keys) 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 @@ -92,12 +97,6 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); - - if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now - { - if (!m_NTCP2Keys) NewNTCP2Keys (); - UpdateNTCP2Address (true); - } } void RouterContext::UpdateRouterInfo () diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 21f7132f..95e88963 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -176,13 +176,13 @@ namespace data auto address = std::make_shared
(); s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->date, sizeof (address->date)); - bool isNtcp2 = false; + bool isNTCP2Only = 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; + if (transportStyleLen > 4 && transportStyle[4] == '2') isNTCP2Only= true; } else if (!strcmp (transportStyle, "SSU")) { @@ -293,7 +293,8 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports && (!isNtcp2 || address->IsPublishedNTCP2 ())) // we ignore unpublished NTCP2 only addresses + if (isNTCP2Only && address->ntcp2) address->ntcp2->isNTCP2Only = true; + if (supportedTransports) { addresses->push_back(address); m_SupportedTransports |= supportedTransports; @@ -705,6 +706,7 @@ namespace data addr->cost = 14; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); + addr->ntcp2->isNTCP2Only = true; // NTCP2 only address memcpy (addr->ntcp2->staticKey, staticKey, 32); memcpy (addr->ntcp2->iv, iv, 16); m_Addresses->push_back(std::move(addr)); @@ -863,7 +865,7 @@ namespace data return GetAddress ( [v4only](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportNTCP) && (!v4only || address->host.is_v4 ()); + return (address->transportStyle == eTransportNTCP) && !address->IsNTCP2Only () && (!v4only || address->host.is_v4 ()); }); } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index f95659d7..47a5d680 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -95,6 +95,7 @@ namespace data Tag<32> staticKey; Tag<16> iv; bool isPublished = false; + bool isNTCP2Only = false; }; struct Address @@ -126,6 +127,7 @@ namespace data bool IsNTCP2 () const { return (bool)ntcp2; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; + bool IsNTCP2Only () const { return ntcp2 && ntcp2->isNTCP2Only; }; }; typedef std::list > Addresses; From ee700ac86101d127d568326b3778525039f6aa67 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 15:14:07 -0400 Subject: [PATCH 56/64] fixed incorrect iv for published NTCP2 addresses --- libi2pd/RouterContext.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ee895e32..d9bea661 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) - { - if (!m_NTCP2Keys) 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,13 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); + + if (ntcp2) // we don't store iv in the address if non published so we must update it from keys + { + if (!m_NTCP2Keys) NewNTCP2Keys (); + UpdateNTCP2Address (true); + } + } void RouterContext::UpdateRouterInfo () From a2c41c9e36e83c912450be8351052d3ef09b482c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 15:35:43 -0400 Subject: [PATCH 57/64] allow NTCP2 only transports --- daemon/Daemon.cpp | 5 +++-- libi2pd/Transports.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 1302ebe8..0b88e983 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -289,9 +289,10 @@ namespace i2p if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); i2p::transport::transports.Start(ntcp, ssu); - if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) { + if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2()) LogPrint(eLogInfo, "Daemon: Transports started"); - } else { + else + { LogPrint(eLogError, "Daemon: failed to start Transports"); /** shut down netdb right away */ i2p::transport::transports.Stop(); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 47944fff..cb523545 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -81,6 +81,7 @@ namespace transport bool IsBoundNTCP() const { return m_NTCPServer != nullptr; } bool IsBoundSSU() const { return m_SSUServer != nullptr; } + bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; } bool IsOnline() const { return m_IsOnline; }; void SetOnline (bool online) { m_IsOnline = online; }; From 6d46fc9f9f1a46ce0b7c3bde726fc6ec3e24556e Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 11 Aug 2018 16:08:21 -0400 Subject: [PATCH 58/64] check send frame error code --- libi2pd/NTCP2.cpp | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b54d6cd7..084fe0d6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -465,8 +465,16 @@ namespace transport // TODO: check tsB if (paddingLen > 0) { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + if (paddingLen <= 287 - 64) // session created is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long"); + Terminate (); + } } else SendSessionConfirmed (); @@ -677,7 +685,8 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); + if (ecode != boost::asio::error::operation_aborted) + LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); Terminate (); } else @@ -702,7 +711,8 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); + if (ecode != boost::asio::error::operation_aborted) + LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); Terminate (); } else @@ -805,13 +815,21 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); - m_NumSentBytes += bytes_transferred; - i2p::transport::transports.UpdateSentBytes (bytes_transferred); - delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; - LogPrint (eLogDebug, "NTCP2: Next frame sent"); m_IsSending = false; - SendQueue (); + delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; + + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ()); + } + else + { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_NumSentBytes += bytes_transferred; + i2p::transport::transports.UpdateSentBytes (bytes_transferred); + LogPrint (eLogDebug, "NTCP2: Next frame sent"); + SendQueue (); + } } void NTCP2Session::SendQueue () From 29b91075d28a32132003b78360324fb2b81c71d8 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Sun, 12 Aug 2018 02:36:00 -0400 Subject: [PATCH 59/64] Don't add SSU/NTCP addresses to RI if they are disabled in config (#1220) --- libi2pd/RouterContext.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d9bea661..b2774aa2 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -50,6 +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 ssu; i2p::config::GetOption("ssu", ssu); + bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); @@ -67,8 +69,10 @@ namespace i2p if(ifname4.size()) host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string(); - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); - routerInfo.AddNTCPAddress (host.c_str(), port); + if (ssu) + routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + if (ntcp) + routerInfo.AddNTCPAddress (host.c_str(), port); } if (ipv6) { @@ -81,8 +85,10 @@ namespace i2p if(ifname6.size()) host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string(); - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); - routerInfo.AddNTCPAddress (host.c_str(), port); + if (ssu) + routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + if (ntcp) + routerInfo.AddNTCPAddress (host.c_str(), port); } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | @@ -363,16 +369,19 @@ namespace i2p caps |= i2p::data::RouterInfo::eFloodfill; m_RouterInfo.SetCaps (caps); - // insert NTCP back auto& addresses = m_RouterInfo.GetAddresses (); - for (const auto& addr : addresses) - { - if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU && - addr->host.is_v4 ()) + // insert NTCP back + bool ntcp; i2p::config::GetOption("ntcp", ntcp); + if (ntcp) { + for (const auto& addr : addresses) { - // insert NTCP address with host/port from SSU - m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port); - break; + if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU && + addr->host.is_v4 ()) + { + // insert NTCP address with host/port from SSU + m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port); + break; + } } } // delete previous introducers From d36d825ac119d15306d928749894124c0e0326e3 Mon Sep 17 00:00:00 2001 From: xcps Date: Mon, 13 Aug 2018 21:41:43 +0500 Subject: [PATCH 60/64] Update HTTPServer.cpp Fix transport sections in web interface --- daemon/HTTPServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c55714a7..e5509f2b 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "Base.h" #include "FS.h" @@ -577,7 +578,7 @@ namespace http { } if (!tmp_s.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s.str () << "

\r\n
\r\n"; } if (!tmp_s6.str ().empty ()) From 634101ceb598a2d4b8b6ff799c2e070d21254882 Mon Sep 17 00:00:00 2001 From: xcps Date: Mon, 13 Aug 2018 22:29:58 +0500 Subject: [PATCH 61/64] Update HTTPServer.cpp Fix transport sections in web interface 2 --- daemon/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index e5509f2b..cda3f2ec 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -578,7 +578,7 @@ namespace http { } if (!tmp_s.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s.str () << "

\r\n
\r\n"; } if (!tmp_s6.str ().empty ()) From cd39a52c2543324639fe927a55443e3ff8ac2a37 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Aug 2018 13:43:51 -0400 Subject: [PATCH 62/64] correct endianness for siphash length --- libi2pd/NTCP2.cpp | 22 ++++++++++++---------- libi2pd/NTCP2.h | 6 +++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 084fe0d6..10373715 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -522,14 +522,14 @@ namespace transport m_ReceiveKey = m_Kba; m_SendSipKey = m_Sipkeysab; m_ReceiveSipKey = m_Sipkeysba; - memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); - memcpy (m_SendIV, m_Sipkeysab + 16, 8); + memcpy (m_ReceiveIV.buf, m_Sipkeysba + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysab + 16, 8); Established (); ReceiveLength (); // TODO: remove - //m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); - //SendQueue (); + // m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); + // SendQueue (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -597,8 +597,8 @@ namespace transport m_ReceiveKey = m_Kab; m_SendSipKey = m_Sipkeysba; m_ReceiveSipKey = m_Sipkeysab; - memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); - memcpy (m_SendIV, m_Sipkeysba + 16, 8); + memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); // process RI if (buf[0] != eNTCP2BlkRouterInfo) @@ -691,8 +691,9 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); - m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); + i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); + // m_NextRecivedLen comes from the network in BigEndian + m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ m_ReceiveIV.key; LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; @@ -803,8 +804,9 @@ namespace transport CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; m_NextSendBuffer = new uint8_t[len + 16 + 2]; i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); - i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_SendSipKey); - htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); + i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); + // length must be in BigEndian + htobe16buf (m_NextSendBuffer, (len + 16) ^ m_SendIV.key); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b5540b43..2be3f144 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -170,7 +170,11 @@ namespace transport const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; - uint8_t m_ReceiveIV[8], m_SendIV[8]; + union + { + uint8_t buf[8]; + uint16_t key; + } m_ReceiveIV, m_SendIV; uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; i2p::I2NPMessagesHandler m_Handler; From 49a44fc92edb8b8ae5a56d47e5131fca4f4f8555 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Aug 2018 14:07:57 -0400 Subject: [PATCH 63/64] assume siphash IV in Litte Endian --- libi2pd/NTCP2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 10373715..36ca1dac 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -693,7 +693,7 @@ namespace transport { i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); // m_NextRecivedLen comes from the network in BigEndian - m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ m_ReceiveIV.key; + m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; @@ -806,7 +806,7 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); // length must be in BigEndian - htobe16buf (m_NextSendBuffer, (len + 16) ^ m_SendIV.key); + htobe16buf (m_NextSendBuffer, (len + 16) ^ le16toh (m_SendIV.key)); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message From 86782aeb1bf9f8adced25fe52e79b7d1c012e27c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 14 Aug 2018 11:27:27 -0400 Subject: [PATCH 64/64] don't send RouterInfo twice --- libi2pd/NTCP2.cpp | 7 ++++++- libi2pd/NTCP2.h | 2 ++ libi2pd/TransportSession.h | 1 + libi2pd/Transports.cpp | 11 +++++++---- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 36ca1dac..b54a83ef 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -644,7 +644,6 @@ namespace transport SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); m_Server.AddNTCP2Session (shared_from_this ()); Established (); - SendRouterInfo (); ReceiveLength (); } else @@ -919,6 +918,12 @@ namespace transport SendQueue (); } + void NTCP2Session::SendLocalRouterInfo () + { + if (!IsOutgoing ()) // we send it in SessionConfirmed + SendRouterInfo (); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_TerminationTimer (m_Service) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 2be3f144..3e202dc5 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -120,6 +120,8 @@ namespace transport void ClientLogin (); // Alice void ServerLogin (); // Bob + + void SendLocalRouterInfo (); // after handshake void SendI2NPMessages (const std::vector >& msgs); private: diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index 62bed352..49067ce2 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -79,6 +79,7 @@ namespace transport bool IsTerminationTimeoutExpired (uint64_t ts) const { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); }; + virtual void SendLocalRouterInfo () { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; virtual void SendI2NPMessages (const std::vector >& msgs) = 0; protected: diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 922625d2..6a833ae0 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -401,7 +401,7 @@ namespace transport { if (peer.router) // we have RI already { - if (!peer.numAttempts) // NTCP + if (!peer.numAttempts) // NTCP2 { peer.numAttempts++; if (m_NTCP2Server) // we support NTCP2 @@ -415,7 +415,10 @@ namespace transport return true; } } - // otherwise NTCP1 + } + if (peer.numAttempts == 1) // NTCP1 + { + peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { @@ -473,7 +476,7 @@ namespace transport else LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU"); } - if (peer.numAttempts == 1)// SSU + if (peer.numAttempts == 2)// SSU { peer.numAttempts++; if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ())) @@ -736,7 +739,7 @@ namespace transport sendDatabaseStore = false; // we have it in the list already } if (sendDatabaseStore) - session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); + session->SendLocalRouterInfo (); else session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds it->second.sessions.push_back (session);