diff --git a/Garlic.cpp b/Garlic.cpp index 7c24bb79..50da90a3 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -5,6 +5,7 @@ #include "ElGamal.h" #include "RouterContext.h" #include "Timestamp.h" +#include "Streaming.h" #include "Garlic.h" namespace i2p @@ -158,5 +159,109 @@ namespace garlic } return ret; } + + void GarlicRouting::HandleGarlicMessage (uint8_t * buf, size_t len) + { + uint32_t length = be32toh (*(uint32_t *)buf); + buf += 4; + std::string sessionTag((const char *)buf, 32); + if (m_SessionTags.count (sessionTag) > 0) + { + // existing session + uint8_t iv[32]; // IV is first 16 bytes + CryptoPP::SHA256().CalculateDigest(iv, buf, 32); + m_Decryption.SetKeyWithIV (m_SessionKey, 32, iv); + m_Decryption.ProcessData(buf + 32, buf + 32, length - 32); + HandleAESBlock (buf + 32, length - 32); + } + else + { + // new session + ElGamalBlock elGamal; + i2p::crypto::ElGamalDecrypt (i2p::context.GetLeaseSetPrivateKey (), buf, (uint8_t *)&elGamal, true); + memcpy (m_SessionKey, elGamal.sessionKey, 32); + uint8_t iv[32]; // IV is first 16 bytes + CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); + m_Decryption.SetKeyWithIV (m_SessionKey, 32, iv); + m_Decryption.ProcessData(buf + 514, buf + 514, length - 514); + HandleAESBlock (buf + 514, length - 514); + } + + } + + void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len) + { + uint16_t tagCount = be16toh (*(uint16_t *)buf); + buf += 2; + for (int i = 0; i < tagCount; i++) + m_SessionTags.insert (std::string ((const char *)(buf + i*32), 32)); + buf += tagCount*32; + uint32_t payloadSize = be32toh (*(uint32_t *)buf); + buf += 4; + buf += 32;// payload hash. TODO: verify it + if (*buf) // session key? + buf += 32; // new session key + buf++; // flag + // payload + HandleGarlicPayload (buf, payloadSize); + } + + void GarlicRouting::HandleGarlicPayload (uint8_t * buf, size_t len) + { + int numCloves = buf[0]; + LogPrint (numCloves," cloves"); + buf++; + for (int i = 0; i < numCloves; i++) + { + // delivery instructions + uint8_t flag = buf[0]; + buf++; // flag + if (flag & 0x80) // encrypted? + { + // TODO: implement + LogPrint ("Clove encrypted"); + buf += 32; + } + GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); + switch (deliveryType) + { + case eGarlicDeliveryTypeLocal: + LogPrint ("Garlic type local"); + i2p::HandleI2NPMessage (buf, len); + break; + case eGarlicDeliveryTypeDestination: + { + LogPrint ("Garlic type destination"); + i2p::data::IdentHash destination (buf); + buf += 32; + // we assume streaming protocol for destination + // later on we should let destination decide + I2NPHeader * header = (I2NPHeader *)buf; + if (header->typeID == eI2NPData) + i2p::stream::HandleDataMessage (&destination, buf + sizeof (I2NPHeader), be16toh (header->size)); + else + LogPrint ("Unexpected I2NP garlic message ", (int)header->typeID); + break; + } + case eGarlicDeliveryTypeRouter: + LogPrint ("Garlic type router not implemented"); + // TODO: implement + buf += 32; + break; + case eGarlicDeliveryTypeTunnel: + LogPrint ("Garlic type tunnel not implemented"); + // TODO: implement + buf += 4; + buf += 32; + break; + default: + LogPrint ("Unknow garlic delivery type ", (int)deliveryType); + } + buf += GetI2NPMessageLength (buf); // I2NP + buf += 4; // CloveID + buf += 8; // Date + buf += 3; // Certificate + } + } } } diff --git a/Garlic.h b/Garlic.h index 2116dc56..cdc251f6 100644 --- a/Garlic.h +++ b/Garlic.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -65,11 +66,23 @@ namespace garlic GarlicRouting (); ~GarlicRouting (); + void HandleGarlicMessage (uint8_t * buf, size_t len); + I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); + + private: + + void HandleAESBlock (uint8_t * buf, size_t len); + void HandleGarlicPayload (uint8_t * buf, size_t len); private: + // outgoing sessions std::map m_Sessions; + // incoming session + uint8_t m_SessionKey[32]; + std::set m_SessionTags; + CryptoPP::CBC_Mode::Decryption m_Decryption; }; extern GarlicRouting routing; diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index ddf4f43b..58622fb8 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -11,6 +11,7 @@ #include "Tunnel.h" #include "base64.h" #include "Transports.h" +#include "Garlic.h" #include "I2NPProtocol.h" namespace i2p @@ -362,6 +363,12 @@ namespace i2p i2p::DeleteI2NPMessage (msg); } } + + size_t GetI2NPMessageLength (uint8_t * msg) + { + I2NPHeader * header = (I2NPHeader *)msg; + return be16toh (header->size) + sizeof (I2NPHeader); + } void HandleI2NPMessage (uint8_t * msg, size_t len) { @@ -375,6 +382,7 @@ namespace i2p { case eI2NPGarlic: LogPrint ("Garlic"); + i2p::garlic::routing.HandleGarlicMessage (buf, size); break; break; case eI2NPDeliveryStatus: diff --git a/I2NPProtocol.h b/I2NPProtocol.h index b97312b0..2b85744c 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -130,7 +130,8 @@ namespace i2p I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg); - + + size_t GetI2NPMessageLength (uint8_t * msg); void HandleI2NPMessage (uint8_t * msg, size_t len); void HandleI2NPMessage (I2NPMessage * msg); }