diff --git a/Garlic.cpp b/Garlic.cpp index 50da90a3..7a450c2c 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -29,7 +29,7 @@ namespace garlic delete[] m_SessionTags; } - I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg) + I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet) { I2NPMessage * m = NewI2NPMessage (); size_t len = 0; @@ -46,7 +46,7 @@ namespace garlic buf += 514; // AES block m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); - len += 514 + CreateAESBlock (buf, msg); + len += 514 + CreateAESBlock (buf, msg, leaseSet); } else // existing session { @@ -57,7 +57,7 @@ namespace garlic CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags + m_NextTag*32, 32); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); // AES block - len += 32 + CreateAESBlock (buf, msg); + len += 32 + CreateAESBlock (buf, msg, leaseSet); } m_NextTag++; *(uint32_t *)(m->GetPayload ()) = htobe32 (len); @@ -67,7 +67,7 @@ namespace garlic return m; } - size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, I2NPMessage * msg) + size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet) { size_t blockSize = 0; *(uint16_t *)buf = htobe16 (m_NumTags); // tag count @@ -80,7 +80,7 @@ namespace garlic blockSize += 32; buf[blockSize] = 0; // flag blockSize++; - size_t len = CreateGarlicPayload (buf + blockSize, msg); + size_t len = CreateGarlicPayload (buf + blockSize, msg, leaseSet); *payloadSize = htobe32 (len); CryptoPP::SHA256().CalculateDigest(payloadHash, buf + blockSize, len); blockSize += len; @@ -91,32 +91,25 @@ namespace garlic return blockSize; } - size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg) + size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec size_t size = 0; - payload[size] = 1; // 1 clove + uint8_t * numCloves = payload + size; + *numCloves = 0; size++; - if (m_Destination->IsDestination ()) - { - payload[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination - size++; - memcpy (payload + size, m_Destination->GetIdentHash (), 32); - size += 32; - } - else + + if (leaseSet) // first clove is our leaseSet if presented { - payload[size] = 0;// delivery instructions flag local - size++; - } - memcpy (payload + size, msg->GetBuffer (), msg->GetLength ()); - size += msg->GetLength (); - *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // CloveID - size += 4; - *(uint64_t *)(payload + size) = htobe64 (ts); // Expiration of clove - size += 8; - memset (payload + size, 0, 3); // certificate of clove - size += 3; + size += CreateGarlicClove (payload + size, leaseSet, false); + (*numCloves)++; + } + if (msg) // next clove message ifself if presented + { + size += CreateGarlicClove (payload + size, msg, true); + (*numCloves)++; + } + memset (payload + size, 0, 3); // certificate of message size += 3; *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // MessageID @@ -126,6 +119,34 @@ namespace garlic return size; } + size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination) + { + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec + size_t size = 0; + if (isDestination) + { + buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination + size++; + memcpy (buf + size, m_Destination->GetIdentHash (), 32); + size += 32; + } + else + { + buf[size] = 0;// delivery instructions flag local + size++; + } + + memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); + size += msg->GetLength (); + *(uint32_t *)(buf + size) = htobe32 (m_Rnd.GenerateWord32 ()); // CloveID + size += 4; + *(uint64_t *)(buf + size) = htobe64 (ts); // Expiration of clove + size += 8; + memset (buf + size, 0, 3); // certificate of clove + size += 3; + return size; + } + GarlicRouting routing; GarlicRouting::GarlicRouting () { @@ -138,7 +159,8 @@ namespace garlic m_Sessions.clear (); } - I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg) + I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * msg, I2NPMessage * leaseSet) { if (!destination) return nullptr; auto it = m_Sessions.find (destination->GetIdentHash ()); @@ -151,7 +173,7 @@ namespace garlic m_Sessions[destination->GetIdentHash ()] = session; } - I2NPMessage * ret = session->WrapSingleMessage (msg); + I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet); if (session->GetNumRemainingSessionTags () <= 0) { m_Sessions.erase (destination->GetIdentHash ()); diff --git a/Garlic.h b/Garlic.h index cdc251f6..db1f008d 100644 --- a/Garlic.h +++ b/Garlic.h @@ -40,13 +40,14 @@ namespace garlic GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); ~GarlicRoutingSession (); - I2NPMessage * WrapSingleMessage (I2NPMessage * msg); + I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); int GetNumRemainingSessionTags () const { return m_NumTags - m_NextTag; }; private: - size_t CreateAESBlock (uint8_t * buf, I2NPMessage * msg); - size_t CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg); + size_t CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet); + size_t CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet); + size_t CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination); private: @@ -68,7 +69,8 @@ namespace garlic void HandleGarlicMessage (uint8_t * buf, size_t len); - I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); + I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); private: diff --git a/Streaming.cpp b/Streaming.cpp index 7a8c18ef..84bd9a28 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,17 +1,21 @@ #include #include #include +#include #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" +#include "Tunnel.h" +#include "Timestamp.h" +#include "CryptoConst.h" #include "Streaming.h" namespace i2p { namespace stream { - Stream::Stream (const i2p::data::IdentHash& destination): - m_SendStreamID (0) + Stream::Stream (StreamingDestination * local, const i2p::data::IdentHash& remote): + m_SendStreamID (0), m_LocalDestination (local) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); } @@ -57,8 +61,16 @@ namespace stream LogPrint ("Payload: ", str); } - StreamingDestination m_SharedLocalDestination; - + StreamingDestination * sharedLocalDestination = nullptr; + + StreamingDestination::StreamingDestination () + { + // TODO: read from file later + m_Keys = i2p::data::CreateRandomKeys (); + m_Identity = m_Keys; + m_IdentHash = i2p::data::CalculateIdentHash (m_Identity); + } + void StreamingDestination::HandleNextPacket (const uint8_t * buf, size_t len) { uint32_t sendStreamID = *(uint32_t *)(buf); @@ -83,11 +95,59 @@ namespace stream return nullptr; } } */ - Stream * s = new Stream (destination); + Stream * s = new Stream (this, destination); m_Streams[s->GetRecvStreamID ()] = s; return s; } - + + I2NPMessage * StreamingDestination::CreateLeaseSet () const + { + I2NPMessage * m = NewI2NPMessage (); + I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload (); + memcpy (msg->key, (const uint8_t *)m_IdentHash, 32); + msg->type = 1; // LeaseSet + msg->replyToken = 0; + + uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg); + size_t size = 0; + memcpy (buf + size, &m_Identity, sizeof (m_Identity)); + size += sizeof (m_Identity); // destination + memcpy (buf + size, i2p::context.GetLeaseSetPublicKey (), 256); + size += 256; // encryption key + memset (buf + size, 0, 128); + size += 128; // signing key + auto tunnel = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (tunnel) + { + buf[size] = 1; // 1 lease + size++; // num + memcpy (buf + size, (const uint8_t *)tunnel->GetNextIdentHash (), 32); + size += 32; // tunnel_gw + *(uint32_t *)(buf + size) = htobe32 (tunnel->GetNextTunnelID ()); + size += 4; // tunnel_id + uint64_t ts = tunnel->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; + ts *= 1000; // in milliseconds + *(uint64_t *)(buf + size) = htobe64 (ts); + size += 8; // end_date + } + else + { + buf[size] = 0; // zero leases + size++; // num + } + + CryptoPP::DSA::PrivateKey signingPrivateKey; + signingPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, + CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); + CryptoPP::DSA::Signer signer (signingPrivateKey); + signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, size, buf+ size); + size += 40; // signature + + m->len += size + sizeof (I2NPDatabaseStoreMsg); + FillI2NPMessageHeader (m, eI2NPDatabaseStore); + return m; + } + void HandleDataMessage (i2p::data::IdentHash * destination, const uint8_t * buf, size_t len) { uint32_t length = be32toh (*(uint32_t *)buf); @@ -104,7 +164,8 @@ namespace stream decompressor.Get (uncompressed, uncompressedSize); // then forward to streaming engine // TODO: we have onle one destination, might be more - m_SharedLocalDestination.HandleNextPacket (uncompressed, uncompressedSize); + if (sharedLocalDestination) + sharedLocalDestination->HandleNextPacket (uncompressed, uncompressedSize); } else LogPrint ("Data: protocol ", buf[9], " is not supported"); diff --git a/Streaming.h b/Streaming.h index c75f0b13..6db5ecd0 100644 --- a/Streaming.h +++ b/Streaming.h @@ -3,7 +3,7 @@ #include #include -#include "LeaseSet.h" +#include "Identity.h" #include "I2NPProtocol.h" namespace i2p @@ -22,11 +22,12 @@ namespace stream const uint16_t PACKET_FLAG_ECHO = 0x0200; const uint16_t PACKET_FLAG_NO_ACK = 0x0400; + class StreamingDestination; class Stream { public: - Stream (const i2p::data::IdentHash& destination); + Stream (StreamingDestination * local, const i2p::data::IdentHash& remote); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; @@ -35,18 +36,27 @@ namespace stream private: uint32_t m_SendStreamID, m_RecvStreamID; + StreamingDestination * m_LocalDestination; }; class StreamingDestination { public: + StreamingDestination (); + + const i2p::data::Keys GetKeys () const { return m_Keys; }; + I2NPMessage * CreateLeaseSet () const; + Stream * CreateNewStream (const i2p::data::IdentHash& destination); void HandleNextPacket (const uint8_t * buf, size_t len); - + private: std::map m_Streams; + i2p::data::Keys m_Keys; + i2p::data::Identity m_Identity; + i2p::data::IdentHash m_IdentHash; }; // assuming data is I2CP message