Browse Source

complete Bob side of NTCP2

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

63
libi2pd/NTCP2.cpp

@ -41,7 +41,7 @@ namespace transport @@ -41,7 +41,7 @@ namespace transport
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[] =
{
@ -60,28 +60,28 @@ namespace transport @@ -60,28 +60,28 @@ namespace transport
SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, rs, 32);
SHA256_Final (m_H, &ctx);
// h = SHA256(h || pub)
// h = SHA256(h || epub)
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, pub, 32);
SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx);
// x25519 between rs and priv
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);
}
void NTCP2Establisher::KDF1Alice ()
{
KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ());
KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), m_RemoteStaticKey, GetPub ());
}
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_Init (&ctx);
@ -99,7 +99,7 @@ namespace transport @@ -99,7 +99,7 @@ namespace transport
}
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, GetRemotePub (), 32);
SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx);
// x25519 between remote pub and priv
@ -108,6 +108,16 @@ namespace transport @@ -108,6 +108,16 @@ namespace transport
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 ()
{
uint8_t inputKeyMaterial[32];
@ -137,7 +147,9 @@ namespace transport @@ -137,7 +147,9 @@ namespace transport
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false)
{
m_Establisher.reset (new NTCP2Establisher);
auto addr = in_RemoteRouter->GetNTCPAddress ();
if (in_RemoteRouter) // Alice
{
auto addr = in_RemoteRouter->GetNTCP2Address ();
if (addr->ntcp2)
{
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
@ -146,6 +158,7 @@ namespace transport @@ -146,6 +158,7 @@ namespace transport
else
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
}
}
NTCP2Session::~NTCP2Session ()
{
@ -331,7 +344,7 @@ namespace transport @@ -331,7 +344,7 @@ namespace transport
encryption.SetIV (m_Establisher->m_IV);
encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y
// 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);
uint8_t options[16];
memset (options, 0, 16);
@ -342,7 +355,7 @@ namespace transport @@ -342,7 +355,7 @@ namespace transport
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
// fill padding
RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen);
RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
// send message
m_SessionCreatedBufferLen = paddingLen + 64;
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (),
@ -366,7 +379,7 @@ namespace transport @@ -366,7 +379,7 @@ namespace transport
decryption.SetIV (m_Establisher->m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
// 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
uint8_t payload[16];
uint8_t nonce[12];
@ -386,7 +399,7 @@ namespace transport @@ -386,7 +399,7 @@ namespace transport
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed ");
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
Terminate ();
}
}
@ -492,12 +505,12 @@ namespace transport @@ -492,12 +505,12 @@ namespace transport
{
if (ecode)
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ());
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ());
Terminate ();
}
else
{
LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received");
LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received");
// update AD
uint8_t h[80];
memcpy (h, m_Establisher->GetH (), 32);
@ -515,7 +528,8 @@ namespace transport @@ -515,7 +528,8 @@ namespace transport
// part 1
uint8_t nonce[12];
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);
@ -524,7 +538,8 @@ namespace transport @@ -524,7 +538,8 @@ namespace transport
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
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
{
// process RI
if (buf[0] == eNTCP2BlkRouterInfo)
{
@ -554,6 +569,18 @@ namespace transport @@ -554,6 +569,18 @@ namespace transport
Established ();
ReceiveLength ();
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
Terminate ();
}
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
Terminate ();
}
}
}
void NTCP2Session::ClientLogin ()
@ -794,7 +821,7 @@ namespace transport @@ -794,7 +821,7 @@ namespace transport
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);
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 @@ -44,12 +44,14 @@ namespace transport
void KDF1Alice ();
void KDF1Bob ();
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived);
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 KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen);
void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen);
void KDF3Alice (); // for SessionConfirmed part 2
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 ();

2
libi2pd/RouterContext.cpp

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

20
libi2pd/RouterInfo.cpp

@ -873,6 +873,7 @@ namespace data @@ -873,6 +873,7 @@ namespace data
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)
auto addresses = boost::atomic_load (&m_Addresses);
#else
@ -889,6 +890,25 @@ namespace data @@ -889,6 +890,25 @@ namespace data
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
{
if (!m_Profile)

1
libi2pd/RouterInfo.h

@ -142,6 +142,7 @@ namespace data @@ -142,6 +142,7 @@ namespace data
uint64_t GetTimestamp () const { return m_Timestamp; };
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> GetNTCP2Address (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const;

Loading…
Cancel
Save