mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 13:27:17 +01:00
send NTCP2 frame from I2NP messages
This commit is contained in:
parent
7692332f0e
commit
7efb47fed4
|
@ -1174,7 +1174,7 @@ namespace crypto
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AEADChaCha20Poly1305Encrypt (std::vector<std::pair<void*, std::size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
|
void AEADChaCha20Poly1305Encrypt (std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
|
||||||
{
|
{
|
||||||
if (bufs.empty ()) return;
|
if (bufs.empty ()) return;
|
||||||
#if LEGACY_OPENSSL
|
#if LEGACY_OPENSSL
|
||||||
|
@ -1190,8 +1190,8 @@ namespace crypto
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
for (auto& it: bufs)
|
for (auto& it: bufs)
|
||||||
{
|
{
|
||||||
chacha::Chacha20Encrypt (state, (uint8_t *)it.first, it.second);
|
chacha::Chacha20Encrypt (state, it.first, it.second);
|
||||||
polyHash.Update ((uint8_t *)it.first, it.second); // after encryption
|
polyHash.Update (it.first, it.second); // after encryption
|
||||||
size += it.second;
|
size += it.second;
|
||||||
}
|
}
|
||||||
// padding
|
// padding
|
||||||
|
@ -1217,7 +1217,7 @@ namespace crypto
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
|
||||||
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
|
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
|
||||||
for (auto& it: bufs)
|
for (auto& it: bufs)
|
||||||
EVP_EncryptUpdate(ctx, (uint8_t *)it.first, &outlen, (uint8_t *)it.first, it.second);
|
EVP_EncryptUpdate(ctx, it.first, &outlen, it.first, it.second);
|
||||||
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
|
||||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
|
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
|
||||||
EVP_CIPHER_CTX_free (ctx);
|
EVP_CIPHER_CTX_free (ctx);
|
||||||
|
|
|
@ -283,7 +283,7 @@ namespace crypto
|
||||||
// AEAD/ChaCha20/Poly1305
|
// AEAD/ChaCha20/Poly1305
|
||||||
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
|
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
|
||||||
|
|
||||||
void AEADChaCha20Poly1305Encrypt (std::vector<std::pair<void*, std::size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
|
void AEADChaCha20Poly1305Encrypt (std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation);
|
||||||
|
|
|
@ -899,14 +899,9 @@ namespace transport
|
||||||
m_Handler.Flush ();
|
m_Handler.Flush ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len)
|
void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf)
|
||||||
{
|
{
|
||||||
if (IsTerminated ()) return;
|
#if OPENSSL_SIPHASH
|
||||||
uint8_t nonce[12];
|
|
||||||
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
|
||||||
m_NextSendBuffer = new uint8_t[len + 16 + 2];
|
|
||||||
i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true);
|
|
||||||
#if OPENSSL_SIPHASH
|
|
||||||
EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
|
EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
|
||||||
EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
|
EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
|
||||||
size_t l = 8;
|
size_t l = 8;
|
||||||
|
@ -915,9 +910,19 @@ namespace transport
|
||||||
i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey);
|
i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey);
|
||||||
#endif
|
#endif
|
||||||
// length must be in BigEndian
|
// length must be in BigEndian
|
||||||
htobe16buf (m_NextSendBuffer, (len + 16) ^ le16toh (m_SendIV.key));
|
htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key));
|
||||||
LogPrint (eLogDebug, "NTCP2: sent length ", len + 16);
|
LogPrint (eLogDebug, "NTCP2: sent length ", frameLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len)
|
||||||
|
{
|
||||||
|
if (IsTerminated ()) return;
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
||||||
|
m_NextSendBuffer = new uint8_t[len + 16 + 2];
|
||||||
|
i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true);
|
||||||
|
SetNextSentFrameLength (len + 16, m_NextSendBuffer);
|
||||||
|
|
||||||
// send message
|
// send message
|
||||||
m_IsSending = true;
|
m_IsSending = true;
|
||||||
boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, len + 16 + 2), boost::asio::transfer_all (),
|
boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, len + 16 + 2), boost::asio::transfer_all (),
|
||||||
|
@ -943,6 +948,72 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
||||||
|
{
|
||||||
|
if (msgs.empty () || IsTerminated ()) return;
|
||||||
|
|
||||||
|
size_t totalLen = 0;
|
||||||
|
std::vector<std::pair<uint8_t *, size_t> > encryptBufs;
|
||||||
|
std::vector<boost::asio::const_buffer> bufs;
|
||||||
|
std::shared_ptr<I2NPMessage> first, last;
|
||||||
|
for (auto& it: msgs)
|
||||||
|
{
|
||||||
|
auto buf = it->GetNTCP2Header ();
|
||||||
|
auto len = it->GetNTCP2Length ();
|
||||||
|
encryptBufs.push_back (std::make_pair (buf, len));
|
||||||
|
if (it == *msgs.begin ()) // first message
|
||||||
|
{
|
||||||
|
// allocate two bytes for length
|
||||||
|
buf -= 2; len += 2;
|
||||||
|
first = it;
|
||||||
|
}
|
||||||
|
if (it == *msgs.rbegin () && it->len + 16 < it->maxLen) // last message
|
||||||
|
{
|
||||||
|
// if it's long enough we add padding and MAC to it
|
||||||
|
// allocate 16 bytes for MAC
|
||||||
|
len += 16;
|
||||||
|
last = it;
|
||||||
|
// create padding block
|
||||||
|
auto paddingLen = CreatePaddingBlock (totalLen + len, buf + len, it->maxLen - len);
|
||||||
|
len += paddingLen;
|
||||||
|
totalLen += paddingLen;
|
||||||
|
it->len += paddingLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufs.push_back (boost::asio::buffer (buf, len));
|
||||||
|
totalLen += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
||||||
|
if (last)
|
||||||
|
i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, last->GetNTCP2Header () + last->GetNTCP2Length ());
|
||||||
|
else // last block was not enough for MAC
|
||||||
|
{
|
||||||
|
// allocate send buffer
|
||||||
|
m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently
|
||||||
|
// crate padding block
|
||||||
|
auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
|
||||||
|
// and padding block to encrypt and send
|
||||||
|
encryptBufs.push_back (std::make_pair (m_NextSendBuffer, paddingLen));
|
||||||
|
i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, m_NextSendBuffer + paddingLen);
|
||||||
|
bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16));
|
||||||
|
totalLen += paddingLen;
|
||||||
|
}
|
||||||
|
SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 2); // right before first block
|
||||||
|
|
||||||
|
// send buffers
|
||||||
|
m_IsSending = true;
|
||||||
|
boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (),
|
||||||
|
std::bind(&NTCP2Session::HandleI2NPMsgsSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||||
|
{
|
||||||
|
HandleNextFrameSent (ecode, bytes_transferred);
|
||||||
|
// msgs get destroyed here
|
||||||
|
}
|
||||||
|
|
||||||
void NTCP2Session::SendQueue ()
|
void NTCP2Session::SendQueue ()
|
||||||
{
|
{
|
||||||
if (!m_SendQueue.empty ())
|
if (!m_SendQueue.empty ())
|
||||||
|
@ -974,20 +1045,27 @@ namespace transport
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// add padding block
|
// add padding block
|
||||||
int paddingSize = (s*NTCP2_MAX_PADDING_RATIO)/100;
|
s += CreatePaddingBlock (s, payload + s, NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - s);
|
||||||
if (s + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - s -3;
|
|
||||||
if (paddingSize) paddingSize = rand () % paddingSize;
|
|
||||||
payload[s] = eNTCP2BlkPadding; // blk
|
|
||||||
htobe16buf (payload + s + 1, paddingSize); // size
|
|
||||||
s += 3;
|
|
||||||
memset (payload + s, 0, paddingSize);
|
|
||||||
s += paddingSize;
|
|
||||||
// send
|
// send
|
||||||
SendNextFrame (payload, s);
|
SendNextFrame (payload, s);
|
||||||
m_Server.DeleteNTCP2FrameBuffer (buf);
|
m_Server.DeleteNTCP2FrameBuffer (buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (len < 3) return 0;
|
||||||
|
len -= 3;
|
||||||
|
size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
|
||||||
|
if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
|
||||||
|
if (paddingSize > len) paddingSize = len;
|
||||||
|
if (paddingSize) paddingSize = rand () % paddingSize;
|
||||||
|
buf[0] = eNTCP2BlkPadding; // blk
|
||||||
|
htobe16buf (buf + 1, paddingSize); // size
|
||||||
|
memset (buf + 3, 0, paddingSize);
|
||||||
|
return paddingSize + 3;
|
||||||
|
}
|
||||||
|
|
||||||
void NTCP2Session::SendRouterInfo ()
|
void NTCP2Session::SendRouterInfo ()
|
||||||
{
|
{
|
||||||
if (!IsEstablished ()) return;
|
if (!IsEstablished ()) return;
|
||||||
|
|
|
@ -175,8 +175,12 @@ namespace transport
|
||||||
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void ProcessNextFrame (const uint8_t * frame, size_t len);
|
void ProcessNextFrame (const uint8_t * frame, size_t len);
|
||||||
|
|
||||||
|
void SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf);
|
||||||
void SendNextFrame (const uint8_t * payload, size_t len);
|
void SendNextFrame (const uint8_t * payload, size_t len);
|
||||||
void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
void SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
|
void HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||||
|
size_t CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len);
|
||||||
void SendQueue ();
|
void SendQueue ();
|
||||||
void SendRouterInfo ();
|
void SendRouterInfo ();
|
||||||
void SendTermination (NTCP2TerminationReason reason);
|
void SendTermination (NTCP2TerminationReason reason);
|
||||||
|
|
|
@ -53,7 +53,7 @@ int main ()
|
||||||
assert (memcmp (buf1, text, 114) == 0);
|
assert (memcmp (buf1, text, 114) == 0);
|
||||||
// test encryption of multiple buffers
|
// test encryption of multiple buffers
|
||||||
memcpy (buf, text, 114);
|
memcpy (buf, text, 114);
|
||||||
std::vector<std::pair<void*, std::size_t> > bufs{ std::make_pair (buf, 50), std::make_pair (buf + 50, 50), std::make_pair (buf + 100, 14) };
|
std::vector<std::pair<uint8_t*, std::size_t> > bufs{ std::make_pair (buf, 50), std::make_pair (buf + 50, 50), std::make_pair (buf + 100, 14) };
|
||||||
i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
|
i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
|
||||||
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
|
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
|
||||||
assert (memcmp (buf1, text, 114) == 0);
|
assert (memcmp (buf1, text, 114) == 0);
|
||||||
|
|
Loading…
Reference in a new issue