mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-05 01:34:13 +00:00
move handshake messages processing to NTCP2Establisher
This commit is contained in:
parent
86782aeb1b
commit
e4ab51329d
@ -244,6 +244,119 @@ namespace transport
|
||||
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):
|
||||
TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
|
||||
m_Server (server), m_Socket (m_Server.GetService ()),
|
||||
@ -368,52 +481,28 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
// decrypt X
|
||||
i2p::crypto::CBCDecryption decryption;
|
||||
decryption.SetKey (i2p::context.GetIdentHash ());
|
||||
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
|
||||
LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
|
||||
uint16_t paddingLen = 0;
|
||||
if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
|
||||
{
|
||||
if (options[1] == 2)
|
||||
if (paddingLen > 0)
|
||||
{
|
||||
uint16_t paddingLen = bufbe16toh (options + 2);
|
||||
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
|
||||
{
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
|
||||
Terminate ();
|
||||
}
|
||||
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
|
||||
SendSessionCreated ();
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
|
||||
Terminate ();
|
||||
SendSessionCreated ();
|
||||
}
|
||||
else
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,23 +535,9 @@ namespace transport
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
|
||||
m_Establisher->m_SessionCreatedBufferLen = 64;
|
||||
// decrypt Y
|
||||
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
|
||||
uint16_t paddingLen = 0;
|
||||
if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
|
||||
{
|
||||
if (paddingLen > 0)
|
||||
{
|
||||
if (paddingLen <= 287 - 64) // session created is 287 bytes max
|
||||
@ -480,10 +555,7 @@ namespace transport
|
||||
SendSessionConfirmed ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,38 +631,16 @@ namespace transport
|
||||
else
|
||||
{
|
||||
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
|
||||
uint8_t nonce[12];
|
||||
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
|
||||
// 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
|
||||
m_Establisher->KDF3Bob ();
|
||||
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 ();
|
||||
// Bob data phase keys
|
||||
m_SendKey = m_Kba;
|
||||
@ -599,7 +649,7 @@ namespace transport
|
||||
m_ReceiveSipKey = m_Sipkeysab;
|
||||
memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
|
||||
memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
|
||||
|
||||
// payload
|
||||
// process RI
|
||||
if (buf[0] != eNTCP2BlkRouterInfo)
|
||||
{
|
||||
@ -644,19 +694,13 @@ namespace transport
|
||||
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
|
||||
m_Server.AddNTCP2Session (shared_from_this ());
|
||||
Established ();
|
||||
ReceiveLength ();
|
||||
}
|
||||
ReceiveLength ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -691,12 +735,20 @@ namespace transport
|
||||
else
|
||||
{
|
||||
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);
|
||||
LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen);
|
||||
if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
|
||||
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
|
||||
Receive ();
|
||||
if (m_NextReceivedLen >= 16)
|
||||
{
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,11 @@ namespace transport
|
||||
void CreateSessionConfirmedMessagePart1 (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;
|
||||
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*/;
|
||||
|
Loading…
x
Reference in New Issue
Block a user