Browse Source

handle TunnelBuildMessage for ECIES router

pull/1553/merge
orignal 4 years ago
parent
commit
3907c17cf5
  1. 53
      libi2pd/I2NPProtocol.cpp
  2. 1
      libi2pd/I2NPProtocol.h
  3. 35
      libi2pd/RouterContext.cpp
  4. 8
      libi2pd/RouterContext.h
  5. 11
      libi2pd/TunnelConfig.cpp
  6. 2
      libi2pd/TunnelConfig.h

53
libi2pd/I2NPProtocol.cpp

@ -363,37 +363,70 @@ namespace i2p
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
uint8_t retCode = 0;
bool isECIES = i2p::context.IsECIES ();
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && if (i2p::context.AcceptsTunnels () &&
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels && i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded () && !i2p::transport::transports.IsBandwidthExceeded () &&
!i2p::transport::transports.IsTransitBandwidthExceeded ()) !i2p::transport::transports.IsTransitBandwidthExceeded ())
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = isECIES ?
i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) :
i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40); clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40);
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
} }
else else
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30) retCode = 30; // always reject with bandwidth reason (30)
//TODO: fill filler if (isECIES)
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret {
record + BUILD_RESPONSE_RECORD_HASH_OFFSET); memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
}
else
{
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
}
// encrypt reply // encrypt reply
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++)
{ {
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); if (isECIES && j == i)
{
uint8_t nonce[12];
memset (nonce, 0, 12);
auto noiseState = std::move (i2p::context.GetCurrentNoiseState ());
if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
return false;
}
}
else
{
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
}
} }
return true; return true;
} }

1
libi2pd/I2NPProtocol.h

@ -98,6 +98,7 @@ namespace i2p
const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464; const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464;
// ECIES BuildResponseRecord // ECIES BuildResponseRecord
const size_t ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511; const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511;
enum I2NPMessageType enum I2NPMessageType

35
libi2pd/RouterContext.cpp

@ -19,6 +19,7 @@
#include "version.h" #include "version.h"
#include "Log.h" #include "Log.h"
#include "Family.h" #include "Family.h"
#include "TunnelConfig.h"
#include "RouterContext.h" #include "RouterContext.h"
namespace i2p namespace i2p
@ -41,6 +42,13 @@ namespace i2p
CreateNewRouter (); CreateNewRouter ();
m_Decryptor = m_Keys.CreateDecryptor (nullptr); m_Decryptor = m_Keys.CreateDecryptor (nullptr);
UpdateRouterInfo (); UpdateRouterInfo ();
if (IsECIES ())
{
auto initState = new i2p::crypto::NoiseSymmetricState ();
i2p::tunnel::InitBuildRequestRecordNoiseState (*initState);
initState->MixHash (GetIdentity ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || hepk)
m_InitialNoiseState.reset (initState);
}
} }
void RouterContext::CreateNewRouter () void RouterContext::CreateNewRouter ()
@ -673,9 +681,32 @@ namespace i2p
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false; return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
} }
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
{ {
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false; if (!m_Decryptor) return false;
if (IsECIES ())
{
if (!m_InitialNoiseState) return false;
// m_InitialNoiseState is h = SHA256(h || hepk)
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk)
uint8_t sharedSecret[32];
m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false);
m_CurrentNoiseState->MixKey (sharedSecret);
encrypted += 32;
uint8_t nonce[12];
memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, TUNNEL_BUILD_RECORD_SIZE - 16,
m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK, nonce, data, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt
{
LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed");
return false;
}
m_CurrentNoiseState->MixHash (encrypted, TUNNEL_BUILD_RECORD_SIZE); // h = SHA256(h || ciphertext)
return true;
}
else
return m_Decryptor->Decrypt (encrypted, data, ctx, false);
} }
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()

8
libi2pd/RouterContext.h

@ -84,7 +84,7 @@ namespace i2p
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
int GetNetID () const { return m_NetID; }; int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; }; void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
@ -109,7 +109,9 @@ namespace i2p
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
void SetSupportsV6 (bool supportsV6); void SetSupportsV6 (bool supportsV6);
void SetSupportsV4 (bool supportsV4); void SetSupportsV4 (bool supportsV4);
bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; };
std::unique_ptr<i2p::crypto::NoiseSymmetricState>& GetCurrentNoiseState () { return m_CurrentNoiseState; };
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
void UpdateStats (); void UpdateStats ();
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
@ -160,6 +162,8 @@ namespace i2p
std::mutex m_GarlicMutex; std::mutex m_GarlicMutex;
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys; std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys; std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys;
// for ECIESx25519
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_InitialNoiseState, m_CurrentNoiseState;
}; };
extern RouterContext context; extern RouterContext context;

11
libi2pd/TunnelConfig.cpp

@ -127,9 +127,7 @@ namespace tunnel
void TunnelHopConfig::EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor, void TunnelHopConfig::EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx) const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx)
{ {
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars InitBuildRequestRecordNoiseState (*this);
memcpy (m_CK, protocolName, 32); // ck = h = protocol_name || 0
SHA256 (m_CK, 32, m_H); // h = SHA256(h);
uint8_t hepk[32]; uint8_t hepk[32];
encryptor->Encrypt (nullptr, hepk, nullptr, false); encryptor->Encrypt (nullptr, hepk, nullptr, false);
MixHash (hepk, 32); // h = SHA256(h || hepk) MixHash (hepk, 32); // h = SHA256(h || hepk)
@ -150,5 +148,12 @@ namespace tunnel
} }
MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
} }
void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state)
{
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
memcpy (state.m_CK, protocolName, 32); // ck = h = protocol_name || 0
SHA256 (state.m_CK, 32, state.m_H); // h = SHA256(h);
}
} }
} }

2
libi2pd/TunnelConfig.h

@ -45,6 +45,8 @@ namespace tunnel
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx); const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx);
}; };
void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state);
class TunnelConfig class TunnelConfig
{ {
public: public:

Loading…
Cancel
Save