Browse Source

complete Bob side of NTCP2

pull/1221/head
orignal 6 years ago
parent
commit
0ff9c9da27
  1. 135
      libi2pd/NTCP2.cpp
  2. 10
      libi2pd/NTCP2.h
  3. 2
      libi2pd/RouterContext.cpp
  4. 20
      libi2pd/RouterInfo.cpp
  5. 1
      libi2pd/RouterInfo.h

135
libi2pd/NTCP2.cpp

@ -41,7 +41,7 @@ namespace transport
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
} }
void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub) void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub)
{ {
static const uint8_t protocolNameHash[] = static const uint8_t protocolNameHash[] =
{ {
@ -60,28 +60,28 @@ namespace transport
SHA256_Update (&ctx, hh, 32); SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, rs, 32); SHA256_Update (&ctx, rs, 32);
SHA256_Final (m_H, &ctx); SHA256_Final (m_H, &ctx);
// h = SHA256(h || pub) // h = SHA256(h || epub)
SHA256_Init (&ctx); SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32); SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, pub, 32); SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx); SHA256_Final (m_H, &ctx);
// x25519 between rs and priv // x25519 between rs and priv
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); // rs*priv
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial, m_K);
} }
void NTCP2Establisher::KDF1Alice () void NTCP2Establisher::KDF1Alice ()
{ {
KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ()); KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), m_RemoteStaticKey, GetPub ());
} }
void NTCP2Establisher::KDF1Bob () void NTCP2Establisher::KDF1Bob ()
{ {
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), GetRemotePub ()); KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
} }
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
{ {
SHA256_CTX ctx; SHA256_CTX ctx;
SHA256_Init (&ctx); SHA256_Init (&ctx);
@ -99,7 +99,7 @@ namespace transport
} }
SHA256_Init (&ctx); SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32); SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, GetRemotePub (), 32); SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx); SHA256_Final (m_H, &ctx);
// x25519 between remote pub and priv // x25519 between remote pub and priv
@ -108,6 +108,16 @@ namespace transport
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial, m_K);
} }
void NTCP2Establisher::KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen)
{
KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetRemotePub ());
}
void NTCP2Establisher::KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen)
{
KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetPub ());
}
void NTCP2Establisher::KDF3Alice () void NTCP2Establisher::KDF3Alice ()
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
@ -137,14 +147,17 @@ namespace transport
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false)
{ {
m_Establisher.reset (new NTCP2Establisher); m_Establisher.reset (new NTCP2Establisher);
auto addr = in_RemoteRouter->GetNTCPAddress (); if (in_RemoteRouter) // Alice
if (addr->ntcp2)
{ {
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); auto addr = in_RemoteRouter->GetNTCP2Address ();
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); if (addr->ntcp2)
{
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
}
else
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
} }
else
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
} }
NTCP2Session::~NTCP2Session () NTCP2Session::~NTCP2Session ()
@ -331,7 +344,7 @@ namespace transport
encryption.SetIV (m_Establisher->m_IV); encryption.SetIV (m_Establisher->m_IV);
encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y
// encryption key for next block (m_K) // encryption key for next block (m_K)
m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen);
auto paddingLen = rand () % (287 - 64); auto paddingLen = rand () % (287 - 64);
uint8_t options[16]; uint8_t options[16];
memset (options, 0, 16); memset (options, 0, 16);
@ -342,7 +355,7 @@ namespace transport
memset (nonce, 0, 12); // set nonce to zero memset (nonce, 0, 12); // set nonce to zero
i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt
// fill padding // fill padding
RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
// send message // send message
m_SessionCreatedBufferLen = paddingLen + 64; m_SessionCreatedBufferLen = paddingLen + 64;
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (),
@ -366,7 +379,7 @@ namespace transport
decryption.SetIV (m_Establisher->m_IV); decryption.SetIV (m_Establisher->m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
// decryption key for next block (m_K) // decryption key for next block (m_K)
m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); m_Establisher->KDF2Alice (m_SessionRequestBuffer, m_SessionRequestBufferLen);
// decrypt and verify MAC // decrypt and verify MAC
uint8_t payload[16]; uint8_t payload[16];
uint8_t nonce[12]; uint8_t nonce[12];
@ -386,7 +399,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed "); LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
Terminate (); Terminate ();
} }
} }
@ -492,12 +505,12 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
{ {
LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received"); LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received");
// update AD // update AD
uint8_t h[80]; uint8_t h[80];
memcpy (h, m_Establisher->GetH (), 32); memcpy (h, m_Establisher->GetH (), 32);
@ -515,44 +528,58 @@ namespace transport
// part 1 // part 1
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (1, nonce); CreateNonce (1, nonce);
i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 48, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false); // decrypt S if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S
// part 2
// update AD again
memcpy (h + 32, m_SessionConfirmedBuffer, 48);
SHA256 (h, 80, m_Establisher->m_H);
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
m_Establisher->KDF3Bob ();
memset (nonce, 0, 12); // set nonce to 0 again
i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt
// process RI
if (buf[0] == eNTCP2BlkRouterInfo)
{ {
auto size = bufbe16toh (buf.data () + 1); // part 2
if (size <= buf.size () - 3) // update AD again
memcpy (h + 32, m_SessionConfirmedBuffer, 48);
SHA256 (h, 80, m_Establisher->m_H);
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
m_Establisher->KDF3Bob ();
memset (nonce, 0, 12); // set nonce to 0 again
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt
{ {
// TODO: check flag // process RI
i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag if (buf[0] == eNTCP2BlkRouterInfo)
// TODO: process options {
} auto size = bufbe16toh (buf.data () + 1);
if (size <= buf.size () - 3)
{
// TODO: check flag
i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
// TODO: process options
}
else
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
}
else
LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed");
// caclulate new h again for KDF data
memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext
SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext);
KeyDerivationFunctionDataPhase ();
// Bob
m_SendKey = m_Kba;
m_ReceiveKey = m_Kab;
m_SendSipKey = m_Sipkeysba;
m_ReceiveSipKey = m_Sipkeysab;
memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8);
memcpy (m_SendIV, m_Sipkeysba + 16, 8);
Established ();
ReceiveLength ();
}
else else
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); {
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
Terminate ();
}
} }
else else
LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); {
// caclulate new h again for KDF data LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext Terminate ();
SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); }
KeyDerivationFunctionDataPhase ();
// Bob
m_SendKey = m_Kba;
m_ReceiveKey = m_Kab;
m_SendSipKey = m_Sipkeysba;
m_ReceiveSipKey = m_Sipkeysab;
memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8);
memcpy (m_SendIV, m_Sipkeysba + 16, 8);
Established ();
ReceiveLength ();
} }
} }
@ -794,7 +821,7 @@ namespace transport
continue; continue;
} }
LogPrint (eLogInfo, "NTC2P: Start listening TCP port ", address->port); LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCP2Session>(*this); auto conn = std::make_shared<NTCP2Session>(*this);
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
} }

10
libi2pd/NTCP2.h

@ -44,12 +44,14 @@ namespace transport
void KDF1Alice (); void KDF1Alice ();
void KDF1Bob (); void KDF1Bob ();
void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen);
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen);
void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate
void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Alice (); // for SessionConfirmed part 2
void KDF3Bob (); void KDF3Bob ();
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived);
void KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
void CreateEphemeralKey (); void CreateEphemeralKey ();

2
libi2pd/RouterContext.cpp

@ -478,7 +478,7 @@ namespace i2p
if (n2k) if (n2k)
{ {
n2k.seekg (0, std::ios::end); n2k.seekg (0, std::ios::end);
len = fk.tellg(); len = n2k.tellg();
n2k.seekg (0, std::ios::beg); n2k.seekg (0, std::ios::beg);
if (len == sizeof (NTCP2PrivateKeys)) if (len == sizeof (NTCP2PrivateKeys))
{ {

20
libi2pd/RouterInfo.cpp

@ -873,6 +873,7 @@ namespace data
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
{ {
// TODO: make it more gereric using comparator
#if (BOOST_VERSION >= 105300) #if (BOOST_VERSION >= 105300)
auto addresses = boost::atomic_load (&m_Addresses); auto addresses = boost::atomic_load (&m_Addresses);
#else #else
@ -889,6 +890,25 @@ namespace data
return nullptr; return nullptr;
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2Address (bool v4only) const
{
// TODO: implement through GetAddress
#if (BOOST_VERSION >= 105300)
auto addresses = boost::atomic_load (&m_Addresses);
#else
auto addresses = m_Addresses;
#endif
for (const auto& address : *addresses)
{
if (address->IsPublishedNTCP2 ())
{
if (!v4only || address->host.is_v4 ())
return address;
}
}
return nullptr;
}
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{ {
if (!m_Profile) if (!m_Profile)

1
libi2pd/RouterInfo.h

@ -142,6 +142,7 @@ namespace data
uint64_t GetTimestamp () const { return m_Timestamp; }; uint64_t GetTimestamp () const { return m_Timestamp; };
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
std::shared_ptr<const Address> GetNTCPAddress (bool v4only = true) const; std::shared_ptr<const Address> GetNTCPAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetNTCP2Address (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const; std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const; std::shared_ptr<const Address> GetSSUV6Address () const;

Loading…
Cancel
Save