diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 7e154cbf..84df9b56 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -78,18 +78,14 @@ namespace tunnel } // decrypt real records - i2p::crypto::CBCDecryption decryption; hop = m_Config->GetLastHop ()->prev; while (hop) { - decryption.SetKey (hop->replyKey); // decrypt records after current hop TunnelHopConfig * hop1 = hop->next; while (hop1) { - decryption.SetIV (hop->replyIV); - uint8_t * record = records + hop1->recordIndex*TUNNEL_BUILD_RECORD_SIZE; - decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); + hop->DecryptRecord (records, hop1->recordIndex); hop1 = hop1->next; } hop = hop->prev; @@ -132,11 +128,7 @@ namespace tunnel { auto idx = hop1->recordIndex; if (idx >= 0 && idx < msg[0]) - { - uint8_t * record = msg + 1 + idx*TUNNEL_BUILD_RECORD_SIZE; - decryption.SetIV (hop->replyIV); - decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); - } + hop->DecryptRecord (msg + 1, idx); else LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range"); hop1 = hop1->prev; diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index cc612c00..1680a0b1 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -77,6 +77,15 @@ namespace tunnel isGateway = false; } } + + void TunnelHopConfig::DecryptRecord (uint8_t * records, int index) const + { + uint8_t * record = records + index*TUNNEL_BUILD_RECORD_SIZE; + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (replyKey); + decryption.SetIV (replyIV); + decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record); + } void ElGamalTunnelHopConfig::CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) { @@ -104,7 +113,7 @@ namespace tunnel memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); } - bool ElGamalTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) + bool ElGamalTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const { i2p::crypto::CBCDecryption decryption; decryption.SetKey (replyKey); @@ -137,10 +146,8 @@ namespace tunnel MixHash (encrypted, len + 16); // h = SHA256(h || ciphertext) } - bool ECIESTunnelHopConfig::DecryptECIES (const uint8_t * key, const uint8_t * encrypted, size_t len, uint8_t * clearText) + bool ECIESTunnelHopConfig::DecryptECIES (const uint8_t * key, const uint8_t * nonce, const uint8_t * encrypted, size_t len, uint8_t * clearText) const { - uint8_t nonce[12]; - memset (nonce, 0, 12); return i2p::crypto::AEADChaCha20Poly1305 (encrypted, len - 16, m_H, 32, key, nonce, clearText, len - 16, false); // decrypt } @@ -169,9 +176,11 @@ namespace tunnel memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); } - bool LongECIESTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) + bool LongECIESTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const { - if (!DecryptECIES (m_CK, encrypted, TUNNEL_BUILD_RECORD_SIZE, clearText)) + uint8_t nonce[12]; + memset (nonce, 0, 12); + if (!DecryptECIES (m_CK, nonce, encrypted, TUNNEL_BUILD_RECORD_SIZE, clearText)) { LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed"); return false; @@ -214,14 +223,26 @@ namespace tunnel memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); } - bool ShortECIESTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) + bool ShortECIESTunnelHopConfig::DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const { - if (!DecryptECIES (replyKey, encrypted, SHORT_TUNNEL_BUILD_RECORD_SIZE, clearText)) + uint8_t nonce[12]; + memset (nonce, 0, 12); + nonce[4] = recordIndex; // nonce is record index + if (!DecryptECIES (replyKey, nonce, encrypted, SHORT_TUNNEL_BUILD_RECORD_SIZE, clearText)) { LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed"); return false; } return true; } + + void ShortECIESTunnelHopConfig::DecryptRecord (uint8_t * records, int index) const + { + uint8_t * record = records + index*SHORT_TUNNEL_BUILD_RECORD_SIZE; + uint8_t nonce[12]; + memset (nonce, 0, 12); + nonce[4] = index; // nonce is index + i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record); + } } } \ No newline at end of file diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index d4c85558..e356a9f0 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -42,7 +42,8 @@ namespace tunnel virtual bool IsECIES () const { return false; }; virtual void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) = 0; - virtual bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) = 0; + virtual bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const = 0; + virtual void DecryptRecord (uint8_t * records, int index) const; // AES }; struct ElGamalTunnelHopConfig: public TunnelHopConfig @@ -50,7 +51,7 @@ namespace tunnel ElGamalTunnelHopConfig (std::shared_ptr r): TunnelHopConfig (r) {}; void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx); - bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText); + bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const; }; struct ECIESTunnelHopConfig: public TunnelHopConfig, public i2p::crypto::NoiseSymmetricState @@ -59,7 +60,7 @@ namespace tunnel TunnelHopConfig (r) {}; bool IsECIES () const { return true; }; void EncryptECIES (const uint8_t * clearText, size_t len, uint8_t * encrypted); - bool DecryptECIES (const uint8_t * key, const uint8_t * encrypted, size_t len, uint8_t * clearText); + bool DecryptECIES (const uint8_t * key, const uint8_t * nonce, const uint8_t * encrypted, size_t len, uint8_t * clearText) const; }; struct LongECIESTunnelHopConfig: public ECIESTunnelHopConfig @@ -67,7 +68,7 @@ namespace tunnel LongECIESTunnelHopConfig (std::shared_ptr r): ECIESTunnelHopConfig (r) {}; void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx); - bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText); + bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const; }; struct ShortECIESTunnelHopConfig: public ECIESTunnelHopConfig @@ -75,20 +76,21 @@ namespace tunnel ShortECIESTunnelHopConfig (std::shared_ptr r): ECIESTunnelHopConfig (r) {}; void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx); - bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText); + bool DecryptBuildResponseRecord (const uint8_t * encrypted, uint8_t * clearText) const; + void DecryptRecord (uint8_t * records, int index) const override; // Chacha20 }; class TunnelConfig { public: - TunnelConfig (std::vector > peers) // inbound + TunnelConfig (const std::vector >& peers) // inbound { CreatePeers (peers); m_LastHop->SetNextIdent (i2p::context.GetIdentHash ()); } - TunnelConfig (std::vector > peers, + TunnelConfig (const std::vector >& peers, uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) // outbound { CreatePeers (peers); @@ -180,8 +182,7 @@ namespace tunnel private: - template - void CreatePeers (const Peers& peers) + void CreatePeers (const std::vector >& peers) { TunnelHopConfig * prev = nullptr; for (const auto& it: peers)