Browse Source

avoid replay upon SSU packet resend

pull/1550/head
orignal 4 years ago
parent
commit
e50abbb250
  1. 21
      libi2pd/SSUData.cpp
  2. 24
      libi2pd/SSUSession.cpp
  3. 1
      libi2pd/SSUSession.h

21
libi2pd/SSUData.cpp

@ -326,8 +326,7 @@ namespace transport
{ {
Fragment * fragment = new Fragment; Fragment * fragment = new Fragment;
fragment->fragmentNum = fragmentNum; fragment->fragmentNum = fragmentNum;
uint8_t * buf = fragment->buf; uint8_t * payload = fragment->buf + sizeof (SSUHeader);
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_WANT_REPLY; // for compatibility *payload = DATA_FLAG_WANT_REPLY; // for compatibility
payload++; payload++;
*payload = 1; // always 1 message fragment per message *payload = 1; // always 1 message fragment per message
@ -346,14 +345,20 @@ namespace transport
payload += 3; payload += 3;
memcpy (payload, msgBuf, size); memcpy (payload, msgBuf, size);
size += payload - buf; size += payload - fragment->buf;
if (size & 0x0F) // make sure 16 bytes boundary uint8_t rem = size & 0x0F;
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16 if (rem) // make sure 16 bytes boundary
{
auto padding = 16 - rem;
memset (fragment->buf + size, 0, padding);
size += padding;
}
fragment->len = size; fragment->len = size;
fragments.push_back (std::unique_ptr<Fragment> (fragment)); fragments.push_back (std::unique_ptr<Fragment> (fragment));
// encrypt message with session key // encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size); uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
try try
{ {
m_Session.Send (buf, size); m_Session.Send (buf, size);
@ -432,6 +437,7 @@ namespace transport
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
int numResent = 0; int numResent = 0;
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();) for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
@ -445,7 +451,8 @@ namespace transport
{ {
try try
{ {
m_Session.Send (f->buf, f->len); // resend m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
m_Session.Send (buf, f->len); // resend
numResent++; numResent++;
} }
catch (boost::system::system_error& ec) catch (boost::system::system_error& ec)

24
libi2pd/SSUSession.cpp

@ -744,24 +744,30 @@ namespace transport
} }
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len) void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len)
{
FillHeaderAndEncrypt (payloadType, buf, len, buf);
}
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out)
{ {
if (len < sizeof (SSUHeader)) if (len < sizeof (SSUHeader))
{ {
LogPrint (eLogError, "SSU: Unexpected packet length ", len); LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return; return;
} }
SSUHeader * header = (SSUHeader *)buf; SSUHeader * header = (SSUHeader *)out;
RAND_bytes (header->iv, 16); // random iv RAND_bytes (header->iv, 16); // random iv
m_SessionKeyEncryption.SetIV (header->iv); m_SessionKeyEncryption.SetIV (header->iv);
header->flag = payloadType << 4; // MSB is 0 SSUHeader * inHeader = (SSUHeader *)in;
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ()); inHeader->flag = payloadType << 4; // MSB is 0
uint8_t * encrypted = &header->flag; htobe32buf (inHeader->time, i2p::util::GetSecondsSinceEpoch ());
uint16_t encryptedLen = len - (encrypted - buf); uint8_t * encrypted = &header->flag, * clear = &inHeader->flag;
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted); uint16_t encryptedLen = len - (encrypted - out);
// assume actual buffer size is 18 (16 + 2) bytes more m_SessionKeyEncryption.Encrypt (clear, encryptedLen, encrypted);
memcpy (buf + len, header->iv, 16); // assume actual out buffer size is 18 (16 + 2) bytes more
memcpy (out + len, header->iv, 16);
uint16_t netid = i2p::context.GetNetID (); uint16_t netid = i2p::context.GetNetID ();
htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8)); htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac); i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
} }

1
libi2pd/SSUSession.h

@ -138,6 +138,7 @@ namespace transport
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey, void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0); const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out); // with session key
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey); void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len); void DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey); bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);

Loading…
Cancel
Save