avoid replay upon SSU packet resend

This commit is contained in:
orignal 2020-08-08 19:01:55 -04:00
parent 8e25226574
commit e50abbb250
3 changed files with 32 additions and 18 deletions

View File

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

View File

@ -744,27 +744,33 @@ namespace transport
}
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))
{
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
SSUHeader * header = (SSUHeader *)buf;
SSUHeader * header = (SSUHeader *)out;
RAND_bytes (header->iv, 16); // random iv
m_SessionKeyEncryption.SetIV (header->iv);
header->flag = payloadType << 4; // MSB is 0
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
// assume actual buffer size is 18 (16 + 2) bytes more
memcpy (buf + len, header->iv, 16);
SSUHeader * inHeader = (SSUHeader *)in;
inHeader->flag = payloadType << 4; // MSB is 0
htobe32buf (inHeader->time, i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag, * clear = &inHeader->flag;
uint16_t encryptedLen = len - (encrypted - out);
m_SessionKeyEncryption.Encrypt (clear, encryptedLen, encrypted);
// assume actual out buffer size is 18 (16 + 2) bytes more
memcpy (out + len, header->iv, 16);
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);
}
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
{
if (len < sizeof (SSUHeader))

View File

@ -138,6 +138,7 @@ namespace transport
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);
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 DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);