From 3534b9c499f3d0e3ae699232f6a21de5285a49cb Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Dec 2024 20:59:59 -0500 Subject: [PATCH] don't create EVP_CIPHER_CTX for each AEAD/Chacha20/Poly1305 message --- libi2pd/Crypto.cpp | 64 +++++++++++++++++++++++++++++++++-------- libi2pd/Crypto.h | 36 +++++++++++++++++++++-- libi2pd/NTCP2.cpp | 18 ++++++++++-- libi2pd/NTCP2.h | 8 ++++++ libi2pd/SSU2.cpp | 12 ++++++++ libi2pd/SSU2.h | 6 ++++ libi2pd/SSU2Session.cpp | 14 ++++----- 7 files changed, 134 insertions(+), 24 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 794ea324..1b663e41 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -615,13 +615,13 @@ namespace crypto // 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) + static bool AEADChaCha20Poly1305 (EVP_CIPHER_CTX * ctx, 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) { - if (len < msgLen) return false; + if (!ctx || len < msgLen) return false; if (encrypt && len < msgLen + 16) return false; bool ret = true; int outlen = 0; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); if (encrypt) { EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); @@ -651,26 +651,66 @@ namespace crypto EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen); ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0; } + return ret; + } + 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) + { + EVP_CIPHER_CTX * ctx = EVP_CIPHER_CTX_new (); + auto ret = AEADChaCha20Poly1305 (ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, encrypt); EVP_CIPHER_CTX_free (ctx); return ret; } - void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac) + AEADChaCha20Poly1305Encryptor::AEADChaCha20Poly1305Encryptor () + { + m_Ctx = EVP_CIPHER_CTX_new (); + } + + AEADChaCha20Poly1305Encryptor::~AEADChaCha20Poly1305Encryptor () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + + bool AEADChaCha20Poly1305Encryptor::Encrypt (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) + { + return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, true); + } + + void AEADChaCha20Poly1305Encryptor::Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac) { if (bufs.empty ()) return; int outlen = 0; - EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); - EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); - EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_EncryptInit_ex(m_Ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_EncryptInit_ex(m_Ctx, NULL, NULL, key, nonce); for (const auto& it: bufs) - EVP_EncryptUpdate(ctx, it.first, &outlen, it.first, it.second); - EVP_EncryptFinal_ex(ctx, NULL, &outlen); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); - EVP_CIPHER_CTX_free (ctx); + EVP_EncryptUpdate(m_Ctx, it.first, &outlen, it.first, it.second); + EVP_EncryptFinal_ex(m_Ctx, NULL, &outlen); + EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); + } + + AEADChaCha20Poly1305Decryptor::AEADChaCha20Poly1305Decryptor () + { + m_Ctx = EVP_CIPHER_CTX_new (); } + + AEADChaCha20Poly1305Decryptor::~AEADChaCha20Poly1305Decryptor () + { + if (m_Ctx) + EVP_CIPHER_CTX_free (m_Ctx); + } + bool AEADChaCha20Poly1305Decryptor::Decrypt (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) + { + return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, false); + } + void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 1666bfeb..75b259a5 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -187,10 +187,42 @@ namespace crypto }; // 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 - void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad + class AEADChaCha20Poly1305Encryptor + { + public: + AEADChaCha20Poly1305Encryptor (); + ~AEADChaCha20Poly1305Encryptor (); + + bool Encrypt (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); // msgLen is len without tag + + void Encrypt (const std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad + + private: + + EVP_CIPHER_CTX * m_Ctx; + }; + + class AEADChaCha20Poly1305Decryptor + { + public: + + AEADChaCha20Poly1305Decryptor (); + ~AEADChaCha20Poly1305Decryptor (); + + bool Decrypt (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); // msgLen is len without tag + + private: + + EVP_CIPHER_CTX * m_Ctx; + }; + + 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 + // ChaCha20 void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index d0c6b002..76b056cf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -991,7 +991,7 @@ namespace transport i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2); uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; - if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) + if (m_Server.AEADChaCha20Poly1305Decrypt (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen)) { LogPrint (eLogDebug, "NTCP2: Received message decrypted"); ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); @@ -1180,7 +1180,7 @@ namespace transport } uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; - i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers + m_Server.AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block // send buffers @@ -1211,7 +1211,7 @@ namespace transport // encrypt uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; - i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); + m_Server.AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer); // send m_IsSending = true; @@ -1980,5 +1980,17 @@ namespace transport else m_Address4 = addr; } + + void NTCP2Server::AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac) + { + return m_Encryptor.Encrypt (bufs, key, nonce, mac); + } + + bool NTCP2Server::AEADChaCha20Poly1305Decrypt (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) + { + return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 108c58f6..5df4de6e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -272,6 +272,11 @@ namespace transport auto& GetService () { return GetIOService (); }; auto& GetEstablisherService () { return m_EstablisherService.GetService (); }; std::mt19937& GetRng () { return m_Rng; }; + void AEADChaCha20Poly1305Encrypt (const std::vector >& bufs, + const uint8_t * key, const uint8_t * nonce, uint8_t * mac); + bool AEADChaCha20Poly1305Decrypt (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 AddNTCP2Session (std::shared_ptr session, bool incoming = false); void RemoveNTCP2Session (std::shared_ptr session); @@ -309,9 +314,12 @@ namespace transport uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; std::unique_ptr m_ProxyEndpoint; + std::shared_ptr m_Address4, m_Address6, m_YggdrasilAddress; std::mt19937 m_Rng; EstablisherService m_EstablisherService; + i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; + i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; public: diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index f53f9dd0..cbd6d38e 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -1516,6 +1516,18 @@ namespace transport } } + bool SSU2Server::AEADChaCha20Poly1305Encrypt (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) + { + return m_Encryptor.Encrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } + + bool SSU2Server::AEADChaCha20Poly1305Decrypt (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) + { + return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len); + } + void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 715e72ab..d6ff415b 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -82,6 +82,10 @@ namespace transport bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); std::mt19937& GetRng () { return m_Rng; } + bool AEADChaCha20Poly1305Encrypt (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 AEADChaCha20Poly1305Decrypt (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 IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; void AdjustTimeOffset (int64_t offset, std::shared_ptr from); @@ -200,6 +204,8 @@ namespace transport std::unordered_map, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) std::list m_ReceivedPacketsQueue; mutable std::mutex m_ReceivedPacketsQueueMutex; + i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor; + i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor; // proxy bool m_IsThroughProxy; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index 96f38217..4196e785 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -349,7 +349,7 @@ namespace transport void SSU2Session::Done () { - m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::Terminate, shared_from_this ())); } void SSU2Session::SendLocalRouterInfo (bool update) @@ -357,7 +357,7 @@ namespace transport if (update || !IsOutgoing ()) { auto s = shared_from_this (); - m_Server.GetService ().post ([s]() + boost::asio::post (m_Server.GetService (), [s]() { if (!s->IsEstablished ()) return; uint8_t payload[SSU2_MAX_PACKET_SIZE]; @@ -389,7 +389,7 @@ namespace transport m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); } if (empty) - m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); + boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); } void SSU2Session::PostI2NPMessages () @@ -1455,7 +1455,7 @@ namespace transport uint8_t nonce[12]; CreateNonce (m_SendPacketNum, nonce); uint8_t payload[SSU2_MAX_PACKET_SIZE]; - i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE, true); + m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE); header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8)); header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4)); m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); @@ -1495,8 +1495,8 @@ namespace transport uint32_t packetNum = be32toh (header.h.packetNum); uint8_t nonce[12]; CreateNonce (packetNum, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, payloadSize, header.buf, 16, - m_KeyDataReceive, nonce, payload, payloadSize, false)) + if (!m_Server.AEADChaCha20Poly1305Decrypt (buf + 16, payloadSize, header.buf, 16, + m_KeyDataReceive, nonce, payload, payloadSize)) { LogPrint (eLogWarning, "SSU2: Data AEAD verification failed "); return; @@ -2052,7 +2052,7 @@ namespace transport auto vec = std::make_shared >(len); memcpy (vec->data (), buf, len); auto s = shared_from_this (); - m_Server.GetService ().post ([s, vec, attempts]() + boost::asio::post (m_Server.GetService (), [s, vec, attempts]() { LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1); s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1);