mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 21:37:17 +01:00
handle TunnelBuildMessage for ECIES router
This commit is contained in:
parent
b12fa97a38
commit
3907c17cf5
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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…
Reference in a new issue