mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-18 23:36:39 +01:00
complete Bob side of NTCP2
This commit is contained in:
parent
07e7c2d852
commit
0ff9c9da27
5 changed files with 109 additions and 59 deletions
|
@ -41,7 +41,7 @@ namespace transport
|
||||||
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
|
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[] =
|
static const uint8_t protocolNameHash[] =
|
||||||
{
|
{
|
||||||
|
@ -60,28 +60,28 @@ namespace transport
|
||||||
SHA256_Update (&ctx, hh, 32);
|
SHA256_Update (&ctx, hh, 32);
|
||||||
SHA256_Update (&ctx, rs, 32);
|
SHA256_Update (&ctx, rs, 32);
|
||||||
SHA256_Final (m_H, &ctx);
|
SHA256_Final (m_H, &ctx);
|
||||||
// h = SHA256(h || pub)
|
// h = SHA256(h || epub)
|
||||||
SHA256_Init (&ctx);
|
SHA256_Init (&ctx);
|
||||||
SHA256_Update (&ctx, m_H, 32);
|
SHA256_Update (&ctx, m_H, 32);
|
||||||
SHA256_Update (&ctx, pub, 32);
|
SHA256_Update (&ctx, epub, 32);
|
||||||
SHA256_Final (m_H, &ctx);
|
SHA256_Final (m_H, &ctx);
|
||||||
// x25519 between rs and priv
|
// x25519 between rs and priv
|
||||||
uint8_t inputKeyMaterial[32];
|
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);
|
MixKey (inputKeyMaterial, m_K);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::KDF1Alice ()
|
void NTCP2Establisher::KDF1Alice ()
|
||||||
{
|
{
|
||||||
KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ());
|
KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), m_RemoteStaticKey, GetPub ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::KDF1Bob ()
|
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_CTX ctx;
|
||||||
SHA256_Init (&ctx);
|
SHA256_Init (&ctx);
|
||||||
|
@ -99,7 +99,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
SHA256_Init (&ctx);
|
SHA256_Init (&ctx);
|
||||||
SHA256_Update (&ctx, m_H, 32);
|
SHA256_Update (&ctx, m_H, 32);
|
||||||
SHA256_Update (&ctx, GetRemotePub (), 32);
|
SHA256_Update (&ctx, epub, 32);
|
||||||
SHA256_Final (m_H, &ctx);
|
SHA256_Final (m_H, &ctx);
|
||||||
|
|
||||||
// x25519 between remote pub and priv
|
// x25519 between remote pub and priv
|
||||||
|
@ -108,6 +108,16 @@ namespace transport
|
||||||
MixKey (inputKeyMaterial, m_K);
|
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 ()
|
void NTCP2Establisher::KDF3Alice ()
|
||||||
{
|
{
|
||||||
uint8_t inputKeyMaterial[32];
|
uint8_t inputKeyMaterial[32];
|
||||||
|
@ -137,7 +147,9 @@ namespace transport
|
||||||
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false)
|
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false)
|
||||||
{
|
{
|
||||||
m_Establisher.reset (new NTCP2Establisher);
|
m_Establisher.reset (new NTCP2Establisher);
|
||||||
auto addr = in_RemoteRouter->GetNTCPAddress ();
|
if (in_RemoteRouter) // Alice
|
||||||
|
{
|
||||||
|
auto addr = in_RemoteRouter->GetNTCP2Address ();
|
||||||
if (addr->ntcp2)
|
if (addr->ntcp2)
|
||||||
{
|
{
|
||||||
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
||||||
|
@ -146,6 +158,7 @@ namespace transport
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
|
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NTCP2Session::~NTCP2Session ()
|
NTCP2Session::~NTCP2Session ()
|
||||||
{
|
{
|
||||||
|
@ -331,7 +344,7 @@ namespace transport
|
||||||
encryption.SetIV (m_Establisher->m_IV);
|
encryption.SetIV (m_Establisher->m_IV);
|
||||||
encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y
|
encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y
|
||||||
// encryption key for next block (m_K)
|
// 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);
|
auto paddingLen = rand () % (287 - 64);
|
||||||
uint8_t options[16];
|
uint8_t options[16];
|
||||||
memset (options, 0, 16);
|
memset (options, 0, 16);
|
||||||
|
@ -342,7 +355,7 @@ namespace transport
|
||||||
memset (nonce, 0, 12); // set nonce to zero
|
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
|
i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt
|
||||||
// fill padding
|
// fill padding
|
||||||
RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen);
|
RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
|
||||||
// send message
|
// send message
|
||||||
m_SessionCreatedBufferLen = paddingLen + 64;
|
m_SessionCreatedBufferLen = paddingLen + 64;
|
||||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (),
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (),
|
||||||
|
@ -366,7 +379,7 @@ namespace transport
|
||||||
decryption.SetIV (m_Establisher->m_IV);
|
decryption.SetIV (m_Establisher->m_IV);
|
||||||
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
|
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
|
||||||
// decryption key for next block (m_K)
|
// 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
|
// decrypt and verify MAC
|
||||||
uint8_t payload[16];
|
uint8_t payload[16];
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
|
@ -386,7 +399,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed ");
|
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
|
||||||
Terminate ();
|
Terminate ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +528,8 @@ namespace transport
|
||||||
// part 1
|
// part 1
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (1, nonce);
|
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
|
// part 2
|
||||||
// update AD again
|
// update AD again
|
||||||
memcpy (h + 32, m_SessionConfirmedBuffer, 48);
|
memcpy (h + 32, m_SessionConfirmedBuffer, 48);
|
||||||
|
@ -524,7 +538,8 @@ namespace transport
|
||||||
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
|
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
|
||||||
m_Establisher->KDF3Bob ();
|
m_Establisher->KDF3Bob ();
|
||||||
memset (nonce, 0, 12); // set nonce to 0 again
|
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
|
// process RI
|
||||||
if (buf[0] == eNTCP2BlkRouterInfo)
|
if (buf[0] == eNTCP2BlkRouterInfo)
|
||||||
{
|
{
|
||||||
|
@ -554,6 +569,18 @@ namespace transport
|
||||||
Established ();
|
Established ();
|
||||||
ReceiveLength ();
|
ReceiveLength ();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::ClientLogin ()
|
void NTCP2Session::ClientLogin ()
|
||||||
|
@ -794,7 +821,7 @@ namespace transport
|
||||||
continue;
|
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);
|
auto conn = std::make_shared<NTCP2Session>(*this);
|
||||||
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
|
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,12 +44,14 @@ namespace transport
|
||||||
|
|
||||||
void KDF1Alice ();
|
void KDF1Alice ();
|
||||||
void KDF1Bob ();
|
void KDF1Bob ();
|
||||||
|
void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen);
|
||||||
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived);
|
void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen);
|
||||||
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 KDF3Alice (); // for SessionConfirmed part 2
|
void KDF3Alice (); // for SessionConfirmed part 2
|
||||||
void KDF3Bob ();
|
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 ();
|
void CreateEphemeralKey ();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,7 @@ namespace i2p
|
||||||
if (n2k)
|
if (n2k)
|
||||||
{
|
{
|
||||||
n2k.seekg (0, std::ios::end);
|
n2k.seekg (0, std::ios::end);
|
||||||
len = fk.tellg();
|
len = n2k.tellg();
|
||||||
n2k.seekg (0, std::ios::beg);
|
n2k.seekg (0, std::ios::beg);
|
||||||
if (len == sizeof (NTCP2PrivateKeys))
|
if (len == sizeof (NTCP2PrivateKeys))
|
||||||
{
|
{
|
||||||
|
|
|
@ -873,6 +873,7 @@ namespace data
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
|
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)
|
#if (BOOST_VERSION >= 105300)
|
||||||
auto addresses = boost::atomic_load (&m_Addresses);
|
auto addresses = boost::atomic_load (&m_Addresses);
|
||||||
#else
|
#else
|
||||||
|
@ -889,6 +890,25 @@ namespace data
|
||||||
return nullptr;
|
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
|
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
|
||||||
{
|
{
|
||||||
if (!m_Profile)
|
if (!m_Profile)
|
||||||
|
|
|
@ -142,6 +142,7 @@ namespace data
|
||||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||||
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
|
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> 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> GetSSUAddress (bool v4only = true) const;
|
||||||
std::shared_ptr<const Address> GetSSUV6Address () const;
|
std::shared_ptr<const Address> GetSSUV6Address () const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue