Browse Source

tunnels through ECIES routers

pull/1565/head
orignal 4 years ago
parent
commit
c93ee0d65d
  1. 19
      libi2pd/I2NPProtocol.h
  2. 29
      libi2pd/Timestamp.cpp
  3. 3
      libi2pd/Timestamp.h
  4. 22
      libi2pd/Tunnel.cpp
  5. 88
      libi2pd/TunnelConfig.cpp
  6. 11
      libi2pd/TunnelConfig.h

19
libi2pd/I2NPProtocol.h

@ -81,6 +81,25 @@ namespace i2p @@ -81,6 +81,25 @@ namespace i2p
const size_t BUILD_RESPONSE_RECORD_PADDING_SIZE = 495;
const size_t BUILD_RESPONSE_RECORD_RET_OFFSET = BUILD_RESPONSE_RECORD_PADDING_OFFSET + BUILD_RESPONSE_RECORD_PADDING_SIZE;
// ECIES BuildRequestRecordClearText
const size_t ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
const size_t ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET = ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET = ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET + 32;
const size_t ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET = ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET + 32;
const size_t ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET = ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET + 32;
const size_t ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET = ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET + 32;
const size_t ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET = ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16;
const size_t ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET = ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET + 1;
const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET + 3;
const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET = ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_PADDING_OFFSET = ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464;
// ECIES BuildResponseRecord
const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511;
enum I2NPMessageType
{
eI2NPDummyMsg = 0,

29
libi2pd/Timestamp.cpp

@ -35,15 +35,21 @@ namespace util @@ -35,15 +35,21 @@ namespace util
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint32_t GetLocalHoursSinceEpoch ()
static uint64_t GetLocalSecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::hours>(
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint64_t GetLocalSecondsSinceEpoch ()
static uint32_t GetLocalMinutesSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::seconds>(
return std::chrono::duration_cast<std::chrono::minutes>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint32_t GetLocalHoursSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
@ -178,14 +184,19 @@ namespace util @@ -178,14 +184,19 @@ namespace util
return GetLocalMillisecondsSinceEpoch () + g_TimeOffset*1000;
}
uint32_t GetHoursSinceEpoch ()
{
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;
}
uint64_t GetSecondsSinceEpoch ()
{
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
}
uint32_t GetMinutesSinceEpoch ()
{
return GetLocalMinutesSinceEpoch () + g_TimeOffset/60;
}
uint32_t GetHoursSinceEpoch ()
{
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;
}
void GetCurrentDate (char * date)

3
libi2pd/Timestamp.h

@ -20,8 +20,9 @@ namespace i2p @@ -20,8 +20,9 @@ namespace i2p
namespace util
{
uint64_t GetMillisecondsSinceEpoch ();
uint32_t GetHoursSinceEpoch ();
uint64_t GetSecondsSinceEpoch ();
uint32_t GetMinutesSinceEpoch ();
uint32_t GetHoursSinceEpoch ();
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes

22
libi2pd/Tunnel.cpp

@ -111,7 +111,7 @@ namespace tunnel @@ -111,7 +111,7 @@ namespace tunnel
while (hop)
{
decryption.SetKey (hop->replyKey);
// decrypt records before and including current hop
// decrypt records before and current hop
TunnelHopConfig * hop1 = hop;
while (hop1)
{
@ -119,8 +119,22 @@ namespace tunnel @@ -119,8 +119,22 @@ namespace tunnel
if (idx >= 0 && idx < msg[0])
{
uint8_t * record = msg + 1 + idx*TUNNEL_BUILD_RECORD_SIZE;
decryption.SetIV (hop->replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
if (hop1 == hop && hop1->IsECIES ())
{
uint8_t nonce[12];
memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (record, TUNNEL_BUILD_RECORD_SIZE - 16,
hop->h, 32, hop->ck, nonce, record, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt
{
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
return false;
}
}
else
{
decryption.SetIV (hop->replyIV);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
}
}
else
LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range");
@ -134,7 +148,7 @@ namespace tunnel @@ -134,7 +148,7 @@ namespace tunnel
while (hop)
{
const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET];
uint8_t ret = record[hop->IsECIES () ? ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET : BUILD_RESPONSE_RECORD_RET_OFFSET];
LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret);
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
if (profile)

88
libi2pd/TunnelConfig.cpp

@ -9,6 +9,9 @@ @@ -9,6 +9,9 @@
#include <memory>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "Crypto.h"
#include "Log.h"
#include "Transports.h"
#include "Timestamp.h"
#include "I2PEndian.h"
@ -76,39 +79,86 @@ namespace tunnel @@ -76,39 +79,86 @@ namespace tunnel
}
}
void TunnelHopConfig::CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) const
void TunnelHopConfig::CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx)
{
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, ident->GetIdentHash (), 32);
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, replyIV, 16);
uint8_t flag = 0;
if (isGateway) flag |= 0x80;
if (isEndpoint) flag |= 0x40;
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
auto encryptor = ident->CreateEncryptor (nullptr);
if (encryptor)
if (IsECIES ())
{
if (ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
memcpy (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32);
memcpy (clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32);
memcpy (clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32);
memcpy (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32);
memcpy (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, replyIV, 16);
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
memset (clearText + ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET, 0, 3); // set to 0 for compatibility
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetMinutesSinceEpoch ());
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET, i2p::util::GetSecondsSinceEpoch () + 600); // 10 minutes
htobe32buf (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
memset (clearText + ECIES_BUILD_REQUEST_RECORD_PADDING_OFFSET, 0, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - ECIES_BUILD_REQUEST_RECORD_PADDING_OFFSET);
if (encryptor)
EncryptECIES (encryptor, clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx);
else
}
else
{
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, ident->GetIdentHash (), 32);
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32);
memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, replyIV, 16);
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
if (encryptor)
encryptor->Encrypt (clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx, false);
}
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
}
void TunnelHopConfig::EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx) const
const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx)
{
memset (encrypted, 0, 512); // TODO: implement
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
memcpy (ck, protocolName, 32); // ck = h = protocol_name || 0
SHA256 (ck, 32, h); // h = SHA256(h);
uint8_t hepk[32];
encryptor->Encrypt (nullptr, hepk, nullptr, false);
MixHash (hepk, 32);
auto ephemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
memcpy (encrypted, ephemeralKeys->GetPublicKey (), 32); encrypted += 32;
uint8_t sharedSecret[32];
ephemeralKeys->Agree (hepk, sharedSecret); // x25519(sesk, hepk)
uint8_t keydata[64];
i2p::crypto::HKDF (ck, sharedSecret, 32, "", keydata);
memcpy (ck, keydata, 32);
uint8_t nonce[12];
memset (nonce, 0, 12);
if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, h, 32,
keydata + 32, nonce, encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16, true)) // encrypt
{
LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed");
return;
}
MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
}
void TunnelHopConfig::MixHash (const uint8_t * buf, size_t len)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, h, 32);
SHA256_Update (&ctx, buf, len);
SHA256_Final (h, &ctx);
}
}
}

11
libi2pd/TunnelConfig.h

@ -30,17 +30,20 @@ namespace tunnel @@ -30,17 +30,20 @@ namespace tunnel
TunnelHopConfig * next, * prev;
int recordIndex; // record # in tunnel build message
uint8_t ck[32], h[32]; // for ECIES
TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r);
void SetNextIdent (const i2p::data::IdentHash& ident);
void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent);
void SetNext (TunnelHopConfig * n);
void SetPrev (TunnelHopConfig * p);
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) const;
bool IsECIES () const { return ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; };
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx);
void EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx) const;
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx);
void MixHash (const uint8_t * buf, size_t len);
};
class TunnelConfig

Loading…
Cancel
Save