Browse Source

move handshake messages processing to NTCP2Establisher

pull/1226/head
orignal 6 years ago
parent
commit
e4ab51329d
  1. 240
      libi2pd/NTCP2.cpp
  2. 5
      libi2pd/NTCP2.h

240
libi2pd/NTCP2.cpp

@ -244,6 +244,119 @@ namespace transport
SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext)
} }
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
{
// decrypt X
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (i2p::context.GetIdentHash ());
decryption.SetIV (i2p::context.GetNTCP2IV ());
decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
decryption.GetIV (m_IV); // save IV for SessionCreated
// decryption key for next block
KDF1Bob ();
// verify MAC and decrypt options block (32 bytes), use m_H as AD
uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt
{
if (options[1] == 2)
{
paddingLen = bufbe16toh (options + 2);
m_SessionRequestBufferLen = paddingLen + 64;
m3p2Len = bufbe16toh (options + 4);
// TODO: check tsA
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
return false;
}
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen)
{
m_SessionCreatedBufferLen = 64;
// decrypt Y
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (m_RemoteIdentHash);
decryption.SetIV (m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
// decryption key for next block (m_K)
KDF2Alice ();
// decrypt and verify MAC
uint8_t payload[16];
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt
{
paddingLen = bufbe16toh(payload + 2);
// TODO: check tsB
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce)
{
// update AD
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256_Final (m_H, &ctx);
int paddingLength = m_SessionCreatedBufferLen - 64;
if (paddingLength > 0)
{
SHA256_CTX ctx1;
SHA256_Init (&ctx1);
SHA256_Update (&ctx1, m_H, 32);
SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength);
SHA256_Final (m_H, &ctx1);
}
if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf)
{
// update AD again
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48);
SHA256_Final (m_H, &ctx);
KDF3Bob ();
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
{
// caclulate new h again for KDF data
memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext
SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext);
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
return false;
}
return true;
}
NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter): NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()), m_Server (server), m_Socket (m_Server.GetService ()),
@ -368,52 +481,28 @@ namespace transport
} }
else else
{ {
// decrypt X LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
i2p::crypto::CBCDecryption decryption; uint16_t paddingLen = 0;
decryption.SetKey (i2p::context.GetIdentHash ()); if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
decryption.SetIV (i2p::context.GetNTCP2IV ());
decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ());
decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated
// decryption key for next block
m_Establisher->KDF1Bob ();
// verify MAC and decrypt options block (32 bytes), use m_H as AD
uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt
{ {
if (options[1] == 2) if (paddingLen > 0)
{ {
uint16_t paddingLen = bufbe16toh (options + 2); if (paddingLen <= 287 - 64) // session request is 287 bytes max
m_Establisher->m_SessionRequestBufferLen = paddingLen + 64;
m_Establisher->m3p2Len = bufbe16toh (options + 4);
// TODO: check tsA
if (paddingLen > 0)
{ {
if (paddingLen <= 287 - 64) // session request is 287 bytes max boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
{ std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate ();
}
} }
else else
SendSessionCreated (); {
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate ();
}
} }
else else
{ SendSessionCreated ();
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); }
Terminate ();
}
}
else else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -446,23 +535,9 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
m_Establisher->m_SessionCreatedBufferLen = 64; uint16_t paddingLen = 0;
// decrypt Y if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
i2p::crypto::CBCDecryption decryption; {
decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
decryption.SetIV (m_Establisher->m_IV);
decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
// decryption key for next block (m_K)
m_Establisher->KDF2Alice ();
// decrypt and verify MAC
uint8_t payload[16];
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt
{
uint16_t paddingLen = bufbe16toh(payload + 2);
LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen);
// TODO: check tsB
if (paddingLen > 0) if (paddingLen > 0)
{ {
if (paddingLen <= 287 - 64) // session created is 287 bytes max if (paddingLen <= 287 - 64) // session created is 287 bytes max
@ -480,10 +555,7 @@ namespace transport
SendSessionConfirmed (); SendSessionConfirmed ();
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -559,38 +631,16 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
// update AD
uint8_t h[80];
memcpy (h, m_Establisher->GetH (), 32);
memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256 (h, 64, h);
int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64;
if (paddingLength > 0)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, h, 32);
SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength);
SHA256_Final (h, &ctx);
}
// part 1 // part 1
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (1, nonce); CreateNonce (1, nonce);
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
{ {
// part 2 // part 2
// update AD again
memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48);
SHA256 (h, 80, m_Establisher->m_H);
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
m_Establisher->KDF3Bob ();
memset (nonce, 0, 12); // set nonce to 0 again memset (nonce, 0, 12); // set nonce to 0 again
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ()))
{ {
// caclulate new h again for KDF data
memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext
SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext);
KeyDerivationFunctionDataPhase (); KeyDerivationFunctionDataPhase ();
// Bob data phase keys // Bob data phase keys
m_SendKey = m_Kba; m_SendKey = m_Kba;
@ -599,7 +649,7 @@ namespace transport
m_ReceiveSipKey = m_Sipkeysab; m_ReceiveSipKey = m_Sipkeysab;
memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
// payload
// process RI // process RI
if (buf[0] != eNTCP2BlkRouterInfo) if (buf[0] != eNTCP2BlkRouterInfo)
{ {
@ -644,19 +694,13 @@ namespace transport
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
m_Server.AddNTCP2Session (shared_from_this ()); m_Server.AddNTCP2Session (shared_from_this ());
Established (); Established ();
ReceiveLength (); ReceiveLength ();
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
Terminate (); Terminate ();
}
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -691,12 +735,20 @@ namespace transport
else else
{ {
i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey);
// m_NextRecivedLen comes from the network in BigEndian // m_NextReceivedLen comes from the network in BigEndian
m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen);
if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; if (m_NextReceivedLen >= 16)
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; {
Receive (); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
Receive ();
}
else
{
LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short");
Terminate ();
}
} }
} }

5
libi2pd/NTCP2.h

@ -91,6 +91,11 @@ namespace transport
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
bool ProcessSessionRequestMessage (uint16_t& paddingLen);
bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
BN_CTX * m_Ctx; BN_CTX * m_Ctx;
uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/;

Loading…
Cancel
Save