diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 91b897f5..b54d6cd7 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -142,20 +142,108 @@ namespace transport i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } - void NTCP2Establisher::CreateSessionRequestBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionRequestMessage () { - m_SessionRequestBufferLen = paddingLen + 64; + // create buffer and fill padding + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + m_SessionRequestBufferLen = paddingLength + 64; m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; - RAND_bytes (m_SessionRequestBuffer + 64, paddingLen); + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // encrypt X + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (m_RemoteIdentHash); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X + encryption.GetIV (m_IV); // save IV for SessionCreated + // encryption key for next block + KDF1Alice (); + // fill options + uint8_t options[32]; // actual options size is 16 bytes + memset (options, 0, 16); + options[1] = 2; // ver + htobe16buf (options + 2, paddingLength); // padLen + m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options + htobe16buf (options + 4, m3p2Len); + // 2 bytes reserved + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA + // 4 bytes reserved + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt } - void NTCP2Establisher::CreateSessionCreatedBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionCreatedMessage () { + auto paddingLen = rand () % (287 - 64); m_SessionCreatedBufferLen = paddingLen + 64; m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + // encrypt Y + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (i2p::context.GetIdentHash ()); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y + // encryption key for next block (m_K) + KDF2Bob (); + uint8_t options[16]; + memset (options, 0, 16); + htobe16buf (options + 2, paddingLen); // padLen + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + } + void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (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); + } + // part1 48 bytes + m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + } + + void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) + { + // part 2 + // 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); + // fill and encrypt + uint8_t * buf = m_SessionConfirmedBuffer + 48; + buf[0] = eNTCP2BlkRouterInfo; // block + htobe16buf (buf + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI + buf[3] = 0; // flag + memcpy (buf + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); + KDF3Alice (); + i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, m_K, nonce, buf, m3p2Len, true); // encrypt + // update h again + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, m3p2Len); + SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), @@ -166,6 +254,7 @@ namespace transport m_Establisher.reset (new NTCP2Establisher); if (in_RemoteRouter) // Alice { + m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash (); auto addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { @@ -246,31 +335,7 @@ namespace transport void NTCP2Session::SendSessionRequest () { - // create buffer and fill padding - auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_Establisher->CreateSessionRequestBuffer (paddingLength); - // encrypt X - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionRequestBuffer); // X - encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated - // encryption key for next block - m_Establisher->KDF1Alice (); - // fill options - uint8_t options[32]; // actual options size is 16 bytes - memset (options, 0, 16); - options[1] = 2; // ver - htobe16buf (options + 2, paddingLength); // padLen - m_Establisher->m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options - htobe16buf (options + 4, m_Establisher->m3p2Len); - // 2 bytes reserved - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA - // 4 bytes reserved - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionRequestBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionRequestMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -365,23 +430,7 @@ namespace transport void NTCP2Session::SendSessionCreated () { - auto paddingLen = rand () % (287 - 64); - m_Establisher->CreateSessionCreatedBuffer (paddingLen); - // encrypt Y - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionCreatedBuffer); // Y - // encryption key for next block (m_K) - m_Establisher->KDF2Bob (); - uint8_t options[16]; - memset (options, 0, 16); - htobe16buf (options + 2, paddingLen); // padLen - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionCreatedBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionCreatedMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -444,47 +493,13 @@ namespace transport } } - void NTCP2Session::SendSessionConfirmed () { - // 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); - } - // part1 48 bytes - m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; - CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer, 48, true); // encrypt - // part 2 - // update AD again - memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - buf[0] = eNTCP2BlkRouterInfo; // block - htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI - buf[3] = 0; // flag - memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); - m_Establisher->KDF3Alice (); - memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt - uint8_t tmp[48]; - memcpy (tmp, m_Establisher->m_SessionConfirmedBuffer, 48); - 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); - memcpy (m_Establisher->m_SessionConfirmedBuffer, tmp, 48); - + CreateNonce (1, nonce); // set nonce to 1 + m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); + memset (nonce, 0, 12); // set nonce back to 0 + m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 00f4275e..b5540b43 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -86,12 +86,15 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); - void CreateSessionRequestBuffer (size_t paddingLength); - void CreateSessionCreatedBuffer (size_t paddingLength); + void CreateSessionRequestMessage (); + void CreateSessionCreatedMessage (); + void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); + void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); 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*/; + i2p::data::IdentHash m_RemoteIdentHash; uint16_t m3p2Len; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;