mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 00:00:29 +03:00
process SessionRequest and send SessionCreated for NTCP2
This commit is contained in:
parent
4351a2736c
commit
b5682012d3
@ -8,6 +8,7 @@
|
|||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include "TunnelBase.h"
|
#include "TunnelBase.h"
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
#include "Crypto.h"
|
||||||
#if LEGACY_OPENSSL
|
#if LEGACY_OPENSSL
|
||||||
#include "ChaCha20.h"
|
#include "ChaCha20.h"
|
||||||
#include "Poly1305.h"
|
#include "Poly1305.h"
|
||||||
@ -16,7 +17,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Crypto.h"
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ namespace transport
|
|||||||
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
|
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived)
|
void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived)
|
||||||
{
|
{
|
||||||
static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes
|
static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes
|
||||||
uint8_t h[64];
|
uint8_t h[64];
|
||||||
@ -81,12 +81,12 @@ namespace transport
|
|||||||
// x25519 between rs and priv
|
// x25519 between rs and priv
|
||||||
uint8_t inputKeyMaterial[32];
|
uint8_t inputKeyMaterial[32];
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv
|
i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, ctx); // rs*priv
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
MixKey (inputKeyMaterial, derived);
|
MixKey (inputKeyMaterial, derived);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived)
|
void NTCP2Session::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived)
|
||||||
{
|
{
|
||||||
uint8_t h[64];
|
uint8_t h[64];
|
||||||
memcpy (h, m_H, 32);
|
memcpy (h, m_H, 32);
|
||||||
@ -106,7 +106,7 @@ namespace transport
|
|||||||
// x25519 between remote pub and priv
|
// x25519 between remote pub and priv
|
||||||
uint8_t inputKeyMaterial[32];
|
uint8_t inputKeyMaterial[32];
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx);
|
i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, ctx);
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
MixKey (inputKeyMaterial, derived);
|
MixKey (inputKeyMaterial, derived);
|
||||||
}
|
}
|
||||||
@ -122,11 +122,9 @@ namespace transport
|
|||||||
|
|
||||||
void NTCP2Session::CreateEphemeralKey (uint8_t * pub)
|
void NTCP2Session::CreateEphemeralKey (uint8_t * pub)
|
||||||
{
|
{
|
||||||
uint8_t key[32];
|
RAND_bytes (m_EphemeralPrivateKey, 32);
|
||||||
RAND_bytes (key, 32);
|
|
||||||
i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey);
|
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
i2p::crypto::GetEd25519 ()->ScalarMulB (m_ExpandedPrivateKey, pub, ctx);
|
i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, ctx);
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +146,7 @@ namespace transport
|
|||||||
encryption.GetIV (m_IV); // save IV for SessionCreated
|
encryption.GetIV (m_IV); // save IV for SessionCreated
|
||||||
// encryption key for next block
|
// encryption key for next block
|
||||||
uint8_t key[32];
|
uint8_t key[32];
|
||||||
KeyDerivationFunction1 (m_RemoteStaticKey, x, key);
|
KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key);
|
||||||
// fill options
|
// fill options
|
||||||
uint8_t options[32]; // actual options size is 16 bytes
|
uint8_t options[32]; // actual options size is 16 bytes
|
||||||
memset (options, 0, 16);
|
memset (options, 0, 16);
|
||||||
@ -184,6 +182,96 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
(void) bytes_transferred;
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ());
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// decrypt X
|
||||||
|
i2p::crypto::CBCDecryption decryption;
|
||||||
|
decryption.SetKey (i2p::context.GetIdentHash ());
|
||||||
|
decryption.SetIV (i2p::context.GetNTCP2IV ());
|
||||||
|
decryption.Decrypt (m_SessionRequestBuffer, 32, m_Y);
|
||||||
|
decryption.GetIV (m_IV); // save IV for SessionCreated
|
||||||
|
// decryption key for next block
|
||||||
|
uint8_t key[32];
|
||||||
|
KeyDerivationFunction1 (m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Y, key);
|
||||||
|
// 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, key, nonce, options, 16, false)) // decrypt
|
||||||
|
{
|
||||||
|
uint16_t version = bufbe16toh (options);
|
||||||
|
if (version == 2)
|
||||||
|
{
|
||||||
|
uint16_t paddingLen = bufbe16toh (options + 2);
|
||||||
|
m_SessionRequestBufferLen = paddingLen + 64;
|
||||||
|
// TODO: check tsA
|
||||||
|
if (paddingLen > 0)
|
||||||
|
boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
|
||||||
|
std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
else
|
||||||
|
SendSessionCreated ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", version);
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionRequest padding read error: ", ecode.message ());
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SendSessionCreated ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::SendSessionCreated ()
|
||||||
|
{
|
||||||
|
m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size
|
||||||
|
// generate key pair (y)
|
||||||
|
uint8_t y[32];
|
||||||
|
CreateEphemeralKey (y);
|
||||||
|
// encrypt Y
|
||||||
|
i2p::crypto::CBCEncryption encryption;
|
||||||
|
encryption.SetKey (i2p::context.GetIdentHash ());
|
||||||
|
encryption.SetIV (m_IV);
|
||||||
|
encryption.Encrypt (y, 32, m_SessionCreatedBuffer);
|
||||||
|
// encryption key for next block (m_K)
|
||||||
|
KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K);
|
||||||
|
auto paddingLen = rand () % (287 - 56);
|
||||||
|
uint8_t options[8];
|
||||||
|
memset (options, 0, 8);
|
||||||
|
htobe16buf (options, paddingLen); // padLen
|
||||||
|
htobe32buf (options + 4, 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, 8, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 24, true); // encrypt
|
||||||
|
// fill padding
|
||||||
|
RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen);
|
||||||
|
// send message
|
||||||
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 56), boost::asio::transfer_all (),
|
||||||
|
std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
@ -201,7 +289,7 @@ namespace transport
|
|||||||
decryption.SetIV (m_IV);
|
decryption.SetIV (m_IV);
|
||||||
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y);
|
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y);
|
||||||
// decryption key for next block (m_K)
|
// decryption key for next block (m_K)
|
||||||
KeyDerivationFunction2 (m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K);
|
KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K);
|
||||||
// decrypt and verify MAC
|
// decrypt and verify MAC
|
||||||
uint8_t payload[8];
|
uint8_t payload[8];
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
@ -240,6 +328,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NTCP2Session::SendSessionConfirmed ()
|
void NTCP2Session::SendSessionConfirmed ()
|
||||||
{
|
{
|
||||||
// update AD
|
// update AD
|
||||||
@ -287,11 +376,25 @@ namespace transport
|
|||||||
Terminate (); // TODO
|
Terminate (); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NTCP2: SessionCreated sent");
|
||||||
|
Terminate (); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
void NTCP2Session::ClientLogin ()
|
void NTCP2Session::ClientLogin ()
|
||||||
{
|
{
|
||||||
SendSessionRequest ();
|
SendSessionRequest ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::ServerLogin ()
|
||||||
|
{
|
||||||
|
m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now
|
||||||
|
boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer, 64), boost::asio::transfer_all (),
|
||||||
|
std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
|
||||||
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
NTCP2Server::NTCP2Server ():
|
NTCP2Server::NTCP2Server ():
|
||||||
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service)
|
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service)
|
||||||
{
|
{
|
||||||
|
@ -25,20 +25,25 @@ namespace transport
|
|||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
|
|
||||||
void ClientLogin (); // Alice
|
void ClientLogin (); // Alice
|
||||||
|
void ServerLogin (); // Bob
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) {}; // TODO
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) {}; // TODO
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived);
|
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived);
|
||||||
void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest
|
void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest
|
||||||
void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate
|
void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate
|
||||||
void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2
|
void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2
|
||||||
|
|
||||||
void CreateEphemeralKey (uint8_t * pub);
|
void CreateEphemeralKey (uint8_t * pub);
|
||||||
void SendSessionRequest ();
|
void SendSessionRequest ();
|
||||||
|
void SendSessionCreated ();
|
||||||
void SendSessionConfirmed ();
|
void SendSessionConfirmed ();
|
||||||
|
|
||||||
void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
void HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
void HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
@ -49,8 +54,8 @@ namespace transport
|
|||||||
boost::asio::ip::tcp::socket m_Socket;
|
boost::asio::ip::tcp::socket m_Socket;
|
||||||
bool m_IsEstablished, m_IsTerminated;
|
bool m_IsEstablished, m_IsTerminated;
|
||||||
|
|
||||||
uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key
|
uint8_t m_EphemeralPrivateKey[32]; // x25519
|
||||||
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32];
|
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */;
|
||||||
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;
|
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;
|
||||||
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user