Browse Source

create and handle short tunnel build reply

pull/1677/head
orignal 3 years ago
parent
commit
2c129b6d39
  1. 7
      libi2pd/Garlic.cpp
  2. 3
      libi2pd/Garlic.h
  3. 87
      libi2pd/I2NPProtocol.cpp
  4. 2
      libi2pd/I2NPProtocol.h
  5. 13
      libi2pd/Tunnel.cpp
  6. 8
      libi2pd/TunnelConfig.cpp
  7. 2
      libi2pd/TunnelConfig.h

7
libi2pd/Garlic.cpp

@ -471,8 +471,13 @@ namespace garlic
{ {
uint64_t t; uint64_t t;
memcpy (&t, tag, 8); memcpy (&t, tag, 8);
AddECIESx25519Key (key, t);
}
void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag)
{
auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key); auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key);
m_ECIESx25519Tags.emplace (t, ECIESX25519AEADRatchetIndexTagset{0, tagset}); m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset});
} }
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)

3
libi2pd/Garlic.h

@ -243,7 +243,7 @@ namespace garlic
std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> msg);
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset); uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset);
@ -260,6 +260,7 @@ namespace garlic
protected: protected:
void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag
bool HandleECIESx25519TagMessage (uint8_t * buf, size_t len); // return true if found bool HandleECIESx25519TagMessage (uint8_t * buf, size_t len); // return true if found
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only
virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) = 0; virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) = 0;

87
libi2pd/I2NPProtocol.cpp

@ -660,68 +660,47 @@ namespace i2p
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
// encrypt reply
uint8_t nonce[12];
memset (nonce, 0, 12);
uint8_t * reply = buf + 1;
for (int j = 0; j < num; j++)
{
nonce[4] = j; // nonce is record #
if (j == i)
{
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = 0; // TODO: correct ret code
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
return;
}
}
else
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState.m_CK, nonce, reply);
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
}
// send reply
if (isEndpoint) if (isEndpoint)
{ {
// we are endpoint, create OutboundTunnelBuildReply auto replyMsg = NewI2NPShortMessage ();
auto otbrm = NewI2NPShortMessage (); replyMsg->Concat (buf, len);
auto payload = otbrm->GetPayload (); replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
payload[0] = num; // num
payload[1] = i; // slot
payload +=2;
// reply
htobe16buf (payload, 3); payload += 2; // length, TODO
memset (payload, 0, 3); payload += 3; // ClearText: no options, and zero ret code. TODO
// ShortBuildReplyRecords. Exclude ours
uint8_t * records = buf + 1;
if (i > 0)
{
memcpy (payload, records, i*SHORT_TUNNEL_BUILD_RECORD_SIZE);
payload += i*SHORT_TUNNEL_BUILD_RECORD_SIZE;
records += i*SHORT_TUNNEL_BUILD_RECORD_SIZE;
}
if (i < num-1)
{
memcpy (payload, records, (num-1-i)*SHORT_TUNNEL_BUILD_RECORD_SIZE);
payload += (num-1-i)*SHORT_TUNNEL_BUILD_RECORD_SIZE;
}
otbrm->len += (payload - otbrm->GetPayload ());
otbrm->FillI2NPMessageHeader (eI2NPOutboundTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
uint64_t tag; uint64_t tag;
memcpy (&tag, noiseState.m_CK, 8); memcpy (&tag, noiseState.m_CK, 8);
// send garlic to reply tunnel // we send it to reply tunnel
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
i2p::garlic::WrapECIESX25519Message (otbrm, noiseState.m_CK + 32, tag))); i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
} }
else else
{
// we are participant, encrypt reply
uint8_t nonce[12];
memset (nonce, 0, 12);
uint8_t * reply = buf + 1;
for (int j = 0; j < num; j++)
{
nonce[4] = j; // nonce is record #
if (j == i)
{
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = 0; // TODO: correct ret code
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
return;
}
}
else
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, noiseState.m_CK, nonce, reply);
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
}
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET,
CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
return; return;
} }
record += SHORT_TUNNEL_BUILD_RECORD_SIZE; record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
@ -843,6 +822,7 @@ namespace i2p
HandleVariableTunnelBuildMsg (msgID, buf, size); HandleVariableTunnelBuildMsg (msgID, buf, size);
break; break;
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPShortTunnelBuildReply:
HandleVariableTunnelBuildReplyMsg (msgID, buf, size); HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break; break;
case eI2NPShortTunnelBuild: case eI2NPShortTunnelBuild:
@ -905,6 +885,7 @@ namespace i2p
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
case eI2NPShortTunnelBuild: case eI2NPShortTunnelBuild:
case eI2NPShortTunnelBuildReply:
// forward to tunnel thread // forward to tunnel thread
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;

2
libi2pd/I2NPProtocol.h

@ -136,7 +136,7 @@ namespace i2p
eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24, eI2NPVariableTunnelBuildReply = 24,
eI2NPShortTunnelBuild = 25, eI2NPShortTunnelBuild = 25,
eI2NPOutboundTunnelBuildReply = 26 eI2NPShortTunnelBuildReply = 26
}; };
const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80; const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80;

13
libi2pd/Tunnel.cpp

@ -105,7 +105,16 @@ namespace tunnel
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
} }
else else
{
if (m_Config->IsShort () && m_Config->GetLastHop ())
{
// add garlic key/tag for reply
uint8_t key[32];
uint64_t tag = m_Config->GetLastHop ()->GetGarlicKey (key);
i2p::context.AddECIESx25519Key (key, tag);
}
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
}
} }
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
@ -513,8 +522,10 @@ namespace tunnel
} }
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPShortTunnelBuild:
case eI2NPShortTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
break; break;
default: default:

8
libi2pd/TunnelConfig.cpp

@ -260,5 +260,13 @@ namespace tunnel
nonce[4] = index; // nonce is index nonce[4] = index; // nonce is index
i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record); i2p::crypto::ChaCha20 (record, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, record);
} }
uint64_t ShortECIESTunnelHopConfig::GetGarlicKey (uint8_t * key) const
{
uint64_t tag;
memcpy (&tag, m_CK, 8);
memcpy (key, m_CK + 32, 32);
return tag;
}
} }
} }

2
libi2pd/TunnelConfig.h

@ -44,6 +44,7 @@ namespace tunnel
virtual void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) = 0; virtual void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID) = 0;
virtual bool DecryptBuildResponseRecord (uint8_t * records) const = 0; virtual bool DecryptBuildResponseRecord (uint8_t * records) const = 0;
virtual void DecryptRecord (uint8_t * records, int index) const; // AES virtual void DecryptRecord (uint8_t * records, int index) const; // AES
virtual uint64_t GetGarlicKey (uint8_t * key) const { return 0; }; // return tag
}; };
struct ElGamalTunnelHopConfig: public TunnelHopConfig struct ElGamalTunnelHopConfig: public TunnelHopConfig
@ -83,6 +84,7 @@ namespace tunnel
void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID); void CreateBuildRequestRecord (uint8_t * records, uint32_t replyMsgID);
bool DecryptBuildResponseRecord (uint8_t * records) const; bool DecryptBuildResponseRecord (uint8_t * records) const;
void DecryptRecord (uint8_t * records, int index) const override; // Chacha20 void DecryptRecord (uint8_t * records, int index) const override; // Chacha20
uint64_t GetGarlicKey (uint8_t * key) const override;
}; };
class TunnelConfig class TunnelConfig

Loading…
Cancel
Save