From 0ff9c9da27abb4b04dc032709fe7c6f9bc8022e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 31 Jul 2018 15:41:13 -0400 Subject: [PATCH] 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;