From 065cfe3b9dc5122275d5554b063678f81c708c9d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 3 Mar 2021 15:30:13 -0500 Subject: [PATCH] separate ratchet session for ECIES router --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 66 ++++++++++++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 19 +++++-- libi2pd/RouterContext.cpp | 7 ++- libi2pd/RouterContext.h | 8 ++- 4 files changed, 64 insertions(+), 36 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 81b83477..f956fa67 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -227,7 +227,7 @@ namespace garlic if (!GetOwner ()) return false; // we are Bob // KDF1 - i2p::crypto::InitNoiseIKState (*this, GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk + i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) { @@ -460,7 +460,7 @@ namespace garlic offset += 32; // KDF1 - i2p::crypto::InitNoiseIKState (*this, m_RemoteStaticKey); // bpk + i2p::crypto::InitNoiseIKState (GetNoiseState (), m_RemoteStaticKey); // bpk MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // x25519(aesk, bpk) @@ -520,7 +520,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingMessageForRouter (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Alice, router's bpk is m_RemoteStaticKey - i2p::crypto::InitNoiseNState (*this, m_RemoteStaticKey); + i2p::crypto::InitNoiseNState (GetNoiseState (), m_RemoteStaticKey); size_t offset = 0; m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); memcpy (out + offset, m_EphemeralKeys->GetPublicKey (), 32); @@ -656,7 +656,7 @@ namespace garlic } buf += 32; len -= 32; // KDF for Reply Key Section - i2p::util::SaveStateHelper s(*this); // restore noise state on exit + i2p::util::SaveStateHelper s(GetNoiseState ()); // restore noise state on exit MixHash (tag, 8); // h = SHA256(h || tag) MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; @@ -820,32 +820,6 @@ namespace garlic } return true; } - - bool ECIESX25519AEADRatchetSession::HandleNextMessageForRouter (const uint8_t * buf, size_t len) - { - if (!GetOwner ()) return false; - // we are Bob - i2p::crypto::InitNoiseNState (*this, GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk - MixHash (buf, 32); - uint8_t sharedSecret[32]; - if (!GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) - { - LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); - return false; - } - MixKey (sharedSecret); - buf += 32; len -= 32; - uint8_t nonce[12]; - CreateNonce (0, nonce); - std::vector payload (len - 16); - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt - { - LogPrint (eLogWarning, "Garlic: Payload for router AEAD verification failed"); - return false; - } - HandlePayload (payload.data (), len - 16, nullptr, 0); - return true; - } std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { @@ -1124,6 +1098,38 @@ namespace garlic ts*1000 > m_LastSentTimestamp + ECIESX25519_SEND_EXPIRATION_TIMEOUT*1000; // milliseconds } + RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState): + ECIESX25519AEADRatchetSession (&i2p::context, false) + { + SetNoiseState (initState); + } + + bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len) + { + if (!GetOwner ()) return false; + i2p::crypto::NoiseSymmetricState state (GetNoiseState ()); + // we are Bob + state.MixHash (buf, 32); + uint8_t sharedSecret[32]; + if (!GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); + return false; + } + state.MixKey (sharedSecret); + buf += 32; len -= 32; + uint8_t nonce[12]; + CreateNonce (0, nonce); + std::vector payload (len - 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, state.m_H, 32, state.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt + { + LogPrint (eLogWarning, "Garlic: Payload for router AEAD verification failed"); + return false; + } + HandlePayload (payload.data (), len - 16, nullptr, 0); + return true; + } + std::shared_ptr WrapECIESX25519AEADRatchetMessage (std::shared_ptr msg, const uint8_t * key, uint64_t tag) { auto m = NewI2NPMessage (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 3aaa3d62..bd6d55e3 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -164,7 +164,6 @@ namespace garlic ~ECIESX25519AEADRatchetSession (); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); - bool HandleNextMessageForRouter (const uint8_t * buf, size_t len); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg, bool isForRouter = false); @@ -186,16 +185,21 @@ namespace garlic bool IsTerminated () const { return m_IsTerminated; } uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; + protected: + + i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; }; + void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; }; + void CreateNonce (uint64_t seqn, uint8_t * nonce); + void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset, int index); + private: - void CreateNonce (uint64_t seqn, uint8_t * nonce); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes void InitNewSessionTagset (std::shared_ptr tagsetNsr) const; bool HandleNewIncomingSession (const uint8_t * buf, size_t len); bool HandleNewOutgoingSessionReply (uint8_t * buf, size_t len); bool HandleExistingSessionMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index); - void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset, int index); void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic = true); @@ -237,6 +241,15 @@ namespace garlic } }; + // single session for all incoming messages + class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession + { + public: + + RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState); + bool HandleNextMessage (const uint8_t * buf, size_t len); + }; + std::shared_ptr WrapECIESX25519AEADRatchetMessage (std::shared_ptr msg, const uint8_t * key, uint64_t tag); } } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 6b217ce7..52be93d3 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -48,6 +48,7 @@ namespace i2p auto initState = new i2p::crypto::NoiseSymmetricState (); i2p::crypto::InitNoiseNState (*initState, GetIdentity ()->GetEncryptionPublicKey ()); m_InitialNoiseState.reset (initState); + m_ECIESSession = std::make_shared(*initState); } } @@ -739,8 +740,10 @@ namespace i2p return; } buf += 4; - auto session = std::make_shared(this, false); - session->HandleNextMessageForRouter (buf, len); + if (m_ECIESSession) + m_ECIESSession->HandleNextMessage (buf, len); + else + LogPrint (eLogError, "Router: Session is not set for ECIES router"); } else i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 228da788..afca407a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -21,6 +21,11 @@ namespace i2p { +namespace garlic +{ + class RouterIncomingRatchetSession; +} + const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; const char NTCP2_KEYS[] = "ntcp2.keys"; @@ -42,7 +47,7 @@ namespace i2p eRouterErrorOffline = 2, eRouterErrorSymmetricNAT = 3 }; - + class RouterContext: public i2p::garlic::GarlicDestination { private: @@ -155,6 +160,7 @@ namespace i2p i2p::data::RouterInfo m_RouterInfo; i2p::data::PrivateKeys m_Keys; std::shared_ptr m_Decryptor, m_TunnelDecryptor; + std::shared_ptr m_ECIESSession; uint64_t m_LastUpdateTime; // in seconds bool m_AcceptsTunnels, m_IsFloodfill; std::chrono::time_point m_StartupTime;