From 002b023b29ec706f724d30ebd3c5528400844e81 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 14 Apr 2014 16:24:57 -0400 Subject: [PATCH 1/7] increment outgoing sequence number --- Streaming.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index cb0cc285..1baffd46 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -160,7 +160,7 @@ namespace stream size += 4; // sendStreamID *(uint32_t *)(packet + size) = htobe32 (m_RecvStreamID); size += 4; // receiveStreamID - *(uint32_t *)(packet + size) = htobe32 (m_SequenceNumber); + *(uint32_t *)(packet + size) = htobe32 (m_SequenceNumber++); size += 4; // sequenceNum *(uint32_t *)(packet + size) = 0; // TODO size += 4; // ack Through @@ -224,7 +224,7 @@ namespace stream size += 4; // sendStreamID *(uint32_t *)(packet + size) = htobe32 (m_RecvStreamID); size += 4; // receiveStreamID - *(uint32_t *)(packet + size) = htobe32 (m_SequenceNumber); + *(uint32_t *)(packet + size) = htobe32 (m_SequenceNumber++); size += 4; // sequenceNum *(uint32_t *)(packet + size) = htobe32 (m_LastReceivedSequenceNumber); size += 4; // ack Through @@ -286,7 +286,7 @@ namespace stream } I2NPMessage * msg = i2p::garlic::routing.WrapMessage (m_RemoteLeaseSet, CreateDataMessage (this, buf, len), leaseSet); - if (!m_OutboundTunnel) + if (!m_OutboundTunnel || m_OutboundTunnel->IsFailed ()) m_OutboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel (); if (m_OutboundTunnel) { From 25e16f1693a77b65885c8123e423dc3329b70bae Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Apr 2014 11:53:24 -0400 Subject: [PATCH 2/7] implement session and mac key if shared key is shorter than 64 bytes --- SSU.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index 9946fa28..b398a56c 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "CryptoConst.h" #include "Log.h" #include "Timestamp.h" @@ -38,23 +38,40 @@ namespace ssu void SSUSession::CreateAESandMacKey (const uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey) { CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength()); - if (!dh.Agree (secretKey, m_DHKeysPair->privateKey, pubKey)) + uint8_t sharedKey[64]; + if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) { LogPrint ("Couldn't create shared key"); return; }; - if (secretKey[0] & 0x80) + if (sharedKey[0] & 0x80) { aesKey[0] = 0; - memcpy (aesKey + 1, secretKey, 31); - memcpy (macKey, secretKey + 31, 32); + memcpy (aesKey + 1, sharedKey, 31); + memcpy (macKey, sharedKey + 31, 32); + } + else if (sharedKey[0]) + { + memcpy (aesKey, sharedKey, 32); + memcpy (macKey, sharedKey + 32, 32); } else { - memcpy (aesKey, secretKey, 32); - memcpy (macKey, secretKey + 32, 32); + // find first non-zero byte + uint8_t * nonZero = sharedKey + 1; + while (!*nonZero) + { + nonZero++; + if (nonZero - sharedKey > 32) + { + LogPrint ("First 32 bytes of shared key is all zeros. Ignored"); + return; + } + } + + memcpy (aesKey, nonZero, 32); + CryptoPP::SHA256().CalculateDigest(macKey, nonZero, 64 - (nonZero - sharedKey)); } m_IsSessionKey = true; } From efab8106c622fbf7896c03f8de602e9f22c3a3b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Apr 2014 12:21:18 -0400 Subject: [PATCH 3/7] implement session key if shared key is shorter than 64 bytes --- NTCPSession.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index ad71e3b0..85580813 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -3,7 +3,6 @@ #include "I2PEndian.h" #include #include -#include #include #include "base64.h" #include "Log.h" @@ -35,21 +34,36 @@ namespace ntcp void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) { CryptoPP::DH dh (elgp, elgg); - CryptoPP::SecByteBlock secretKey(dh.AgreedValueLength()); - if (!dh.Agree (secretKey, m_DHKeysPair->privateKey, pubKey)) + uint8_t sharedKey[64]; + if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) { LogPrint ("Couldn't create shared key"); Terminate (); return; }; - if (secretKey[0] & 0x80) + if (sharedKey[0] & 0x80) { aesKey[0] = 0; - memcpy (aesKey + 1, secretKey, 31); + memcpy (aesKey + 1, sharedKey, 31); } - else - memcpy (aesKey, secretKey, 32); + else if (sharedKey[0]) + memcpy (aesKey, sharedKey, 32); + else + { + // find first non-zero byte + uint8_t * nonZero = sharedKey + 1; + while (!*nonZero) + { + nonZero++; + if (nonZero - sharedKey > 32) + { + LogPrint ("First 32 bytes of shared key is all zeros. Ignored"); + return; + } + } + memcpy (aesKey, nonZero, 32); + } } void NTCPSession::Terminate () From 4341d285aa6d97c0e449a021653e83741e0beec2 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 15 Apr 2014 17:44:44 -0400 Subject: [PATCH 4/7] fxied crash --- NTCPSession.cpp | 2 +- SSU.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 85580813..7d53c541 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -34,7 +34,7 @@ namespace ntcp void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) { CryptoPP::DH dh (elgp, elgg); - uint8_t sharedKey[64]; + uint8_t sharedKey[256]; if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) { LogPrint ("Couldn't create shared key"); diff --git a/SSU.cpp b/SSU.cpp index b398a56c..dffd338a 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -38,7 +38,7 @@ namespace ssu void SSUSession::CreateAESandMacKey (const uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey) { CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - uint8_t sharedKey[64]; + uint8_t sharedKey[256]; if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) { LogPrint ("Couldn't create shared key"); From 73d38f530f2eab209d9eb2a6142b324e3e8073bc Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2014 15:54:28 -0400 Subject: [PATCH 5/7] store relay tag if introducer --- SSU.cpp | 34 +++++++++++++++++++++++++++++----- SSU.h | 4 ++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/SSU.cpp b/SSU.cpp index dffd338a..9e4e49ca 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -294,6 +294,7 @@ namespace ssu LogPrint ("SSU is not supported"); return; } + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time memcpy (signedData, x, 256); // x @@ -311,8 +312,14 @@ namespace ssu memcpy (signedData + 512, payload - 6, 6); // remote endpoint IP and port *(uint32_t *)(signedData + 518) = htobe32 (address->host.to_v4 ().to_ulong ()); // our IP *(uint16_t *)(signedData + 522) = htobe16 (address->port); // our port - *(uint32_t *)(payload) = 0; // relay tag, always 0 for now - payload += 4; + uint32_t relayTag = 0; + if (i2p::context.GetRouterInfo ().IsIntroducer ()) + { + rnd.GenerateWord32 (relayTag); + m_Server.AddRelay (relayTag, m_RemoteEndpoint); + } + *(uint32_t *)(payload) = relayTag; + payload += 4; // relay tag *(uint32_t *)(payload) = htobe32 (i2p::util::GetSecondsSinceEpoch ()); // signed on time payload += 4; memcpy (signedData + 524, payload - 8, 8); // relayTag and signed on time @@ -320,7 +327,6 @@ namespace ssu // TODO: fill padding with random data uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv // encrypt signature and 8 bytes padding with newly created session key m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); @@ -929,6 +935,19 @@ namespace ssu m_Socket.close (); } + void SSUServer::AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay) + { + m_Relays[tag] = relay; + } + + SSUSession * SSUServer::FindRelaySession (uint32_t tag) + { + auto it = m_Relays.find (tag); + if (it != m_Relays.end ()) + return FindSession (it->second); + return nullptr; + } + void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) { m_Socket.send_to (boost::asio::buffer (buf, len), to); @@ -968,12 +987,17 @@ namespace ssu if (!router) return nullptr; auto address = router->GetSSUAddress (); if (!address) return nullptr; - auto it = m_Sessions.find (boost::asio::ip::udp::endpoint (address->host, address->port)); + return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); + } + + SSUSession * SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) + { + auto it = m_Sessions.find (e); if (it != m_Sessions.end ()) return it->second; else return nullptr; - } + } SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router, bool peerTest) { diff --git a/SSU.h b/SSU.h index f648f5db..9945ff04 100644 --- a/SSU.h +++ b/SSU.h @@ -157,12 +157,15 @@ namespace ssu void Stop (); SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false); SSUSession * FindSession (const i2p::data::RouterInfo * router); + SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e); void DeleteSession (SSUSession * session); void DeleteAllSessions (); boost::asio::io_service& GetService () { return m_Socket.get_io_service(); }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); + void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay); + SSUSession * FindRelaySession (uint32_t tag); private: @@ -176,6 +179,7 @@ namespace ssu boost::asio::ip::udp::endpoint m_SenderEndpoint; uint8_t m_ReceiveBuffer[2*SSU_MTU]; std::map m_Sessions; + std::map m_Relays; // we are introducer public: // for HTTP only From b873f7c7f1a96775fddfc26d1a22cda05e8a7379 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2014 16:47:56 -0400 Subject: [PATCH 6/7] RelayResponse/RelayIntro --- SSU.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SSU.h | 3 +++ 2 files changed, 83 insertions(+) diff --git a/SSU.cpp b/SSU.cpp index 9e4e49ca..11581752 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -152,6 +152,10 @@ namespace ssu ProcessRelayResponse (buf, len); m_Server.DeleteSession (this); break; + case PAYLOAD_TYPE_RELAY_REQUEST: + LogPrint ("SSU relay request received"); + ProcessRelayIntro (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); + break; case PAYLOAD_TYPE_RELAY_INTRO: LogPrint ("SSU relay intro received"); ProcessRelayIntro (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); @@ -377,6 +381,82 @@ namespace ssu m_Server.Send (buf, 480, m_RemoteEndpoint); } + void SSUSession::ProcessRelayRequest (uint8_t * buf, size_t len) + { + uint32_t relayTag = be32toh (*(uint32_t *)buf); + auto session = m_Server.FindRelaySession (relayTag); + if (session) + { + buf += 4; // relay tag + uint8_t size = *buf; + if (size == 4) + { + buf++; // size + boost::asio::ip::address_v4 address (be32toh (*(uint32_t* )buf)); + buf += 4; // address + uint16_t port = be16toh (*(uint16_t *)buf); + buf += 2; // port + uint8_t challengeSize = *buf; + buf++; // challenge size + buf += challengeSize; + uint8_t * introKey = buf; + buf += 32; // introkey + uint32_t nonce = be32toh (*(uint32_t *)buf); + boost::asio::ip::udp::endpoint from (address, port); + SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint); + SendRelayIntro (session, from); + } + else + LogPrint ("Address size ", size, " is not supported"); + } + } + + void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from, const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to) + { + uint8_t buf[64 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + // Charlie + *payload = 4; + payload++; // size + *(uint32_t *)payload = htobe32 (to.address ().to_v4 ().to_ulong ()); // Charlie's IP + payload += 4; // address + *(uint16_t *)payload = htobe16 (to.port ()); // Charlie's port + payload += 2; // port + // Alice + *payload = 4; + payload++; // size + *(uint32_t *)payload = htobe32 (from.address ().to_v4 ().to_ulong ()); // Alice's IP + payload += 4; // address + *(uint16_t *)payload = htobe16 (from.port ()); // Alice's port + payload += 2; // port + *(uint32_t *)payload = htobe32 (nonce); + + uint8_t iv[16]; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, 64, introKey, iv, introKey); + m_Server.Send (buf, 64, from); + } + + void SSUSession::SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from) + { + if (!session) return; + uint8_t buf[48 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *payload = 4; + payload++; // size + *(uint32_t *)payload = htobe32 (from.address ().to_v4 ().to_ulong ()); // Alice's IP + payload += 4; // address + *(uint16_t *)payload = htobe16 (from.port ()); // Alice's port + payload += 2; // port + *payload = 0; // challenge size + uint8_t iv[16]; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey); + m_Server.Send (buf, 48, session->m_RemoteEndpoint); + } + void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len) { LogPrint ("Relay response received"); diff --git a/SSU.h b/SSU.h index 9945ff04..95198d21 100644 --- a/SSU.h +++ b/SSU.h @@ -99,6 +99,9 @@ namespace ssu void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress); + void ProcessRelayRequest (uint8_t * buf, size_t len); + void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from, const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to); + void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from); void ProcessRelayResponse (uint8_t * buf, size_t len); void ProcessRelayIntro (uint8_t * buf, size_t len); void Established (); From 3b0c03104cc2783534cfe371f536801b848eb3bb Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 16 Apr 2014 18:28:44 -0400 Subject: [PATCH 7/7] introducer support --- RouterInfo.cpp | 3 ++- SSU.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 9a4f8f97..da829c47 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -359,7 +359,8 @@ namespace data memcpy (addr.key, key, 32); m_Addresses.push_back(addr); m_SupportedTransports |= eSSUV4; - m_Caps |= eSSUTesting; // TODO + m_Caps |= eSSUTesting; + m_Caps |= eSSUIntroducer; } void RouterInfo::SetProperty (const char * key, const char * value) diff --git a/SSU.cpp b/SSU.cpp index 11581752..b32bfddb 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -154,7 +154,7 @@ namespace ssu break; case PAYLOAD_TYPE_RELAY_REQUEST: LogPrint ("SSU relay request received"); - ProcessRelayIntro (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); + ProcessRelayRequest (buf + sizeof (SSUHeader), len - sizeof (SSUHeader)); break; case PAYLOAD_TYPE_RELAY_INTRO: LogPrint ("SSU relay intro received");