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 @@ -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,14 +147,17 @@ namespace transport @@ -137,14 +147,17 @@ namespace transport
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false)
{
m_Establisher.reset (new NTCP2Establisher);
auto addr = in_RemoteRouter->GetNTCPAddress ();
if (addr->ntcp2)
if (in_RemoteRouter) // Alice
{
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
auto addr = in_RemoteRouter->GetNTCP2Address ();
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 ()
@ -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,44 +528,58 @@ namespace transport @@ -515,44 +528,58 @@ 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
// 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)
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S
{
auto size = bufbe16toh (buf.data () + 1);
if (size <= buf.size () - 3)
// 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
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
i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
// TODO: process options
}
// process RI
if (buf[0] == eNTCP2BlkRouterInfo)
{
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
LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
Terminate ();
}
}
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 ();
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
Terminate ();
}
}
}
@ -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