From 51e3d5f7bc122d81eb0c0466e3fb3b7511ea4ecd Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 26 Apr 2020 19:27:31 -0400 Subject: [PATCH] create next tagset --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 70 ++++++++++++++++++++++- libi2pd/ECIESX25519AEADRatchetSession.h | 9 +-- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 2a30713e..8d820eb6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -38,7 +38,11 @@ namespace garlic { i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) m_NextIndex++; - if (m_NextIndex >= 65535) m_NextIndex = 0; // TODO: dirty hack, should create new tagset + if (m_NextIndex >= 65535) + { + LogPrint (eLogError, "Garlic: Tagset ", GetTagSetID (), " is empty"); + return 0; + } return m_KeyData.GetTag (); } @@ -251,7 +255,26 @@ namespace garlic uint8_t flag = buf[0]; buf++; // flag if (flag & ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG) { - // TODO: implement + if (!m_NextSendRatchet) return; + uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID + if (((!m_NextSendRatchet->newKey || !m_NextSendRatchet->keyID) && keyID == m_NextSendRatchet->keyID) || + (m_NextSendRatchet->newKey && keyID == m_NextSendRatchet->keyID -1)) + { + if (flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG) + memcpy (m_NextSendRatchet->remote, buf, 32); + uint8_t sharedSecret[32], tagsetKey[32]; + m_NextSendRatchet->key.Agree (m_NextSendRatchet->remote, sharedSecret); + i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32) + auto newTagset = std::make_shared (shared_from_this ()); + newTagset->SetTagSetID (1 + m_NextSendRatchet->keyID + keyID); + newTagset->DHInitialize (m_SendTagset->GetNextRootKey (), tagsetKey); + newTagset->NextSessionTagRatchet (); + m_SendTagset = newTagset; + m_SendForwardKey = false; + LogPrint (eLogDebug, "Garlic: next send tagset ", newTagset->GetTagSetID (), " created"); + } + else + LogPrint (eLogDebug, "Garlic: Unexpected next key ", keyID); } else { @@ -292,6 +315,26 @@ namespace garlic LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created"); } } + + void ECIESX25519AEADRatchetSession::NewNextSendRatchet () + { + auto newTagset = new DHRatchet (); + if (m_NextSendRatchet) + { + newTagset->keyID = m_NextSendRatchet->keyID; + if (!newTagset->newKey || !newTagset->keyID) + { + newTagset->keyID++; + newTagset->newKey = true; + } + else + newTagset->newKey = false; + } + if (newTagset->newKey) + newTagset->key.GenerateKeys (); + m_NextSendRatchet.reset (newTagset); + m_SendForwardKey = true; + } bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { @@ -487,7 +530,9 @@ namespace garlic { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; - } + } + if (index >= ECIESX25519_TAGSET_MAX_NUM_TAGS && !m_SendForwardKey) + NewNextSendRatchet (); return true; } @@ -601,6 +646,11 @@ namespace garlic payloadLen += 6; if (m_NextReceiveRatchet->newKey) payloadLen += 32; } + if (m_SendForwardKey) + { + payloadLen += 6; + if (m_NextSendRatchet->newKey) payloadLen += 32; + } uint8_t paddingSize; RAND_bytes (&paddingSize, 1); paddingSize &= 0x0F; paddingSize++; // 1 - 16 @@ -662,6 +712,20 @@ namespace garlic } m_SendReverseKey = false; } + if (m_SendForwardKey) + { + v[offset] = eECIESx25519BlkNextKey; offset++; + htobe16buf (v.data () + offset, m_NextSendRatchet->newKey ? 35 : 3); offset += 2; + v[offset] = m_NextSendRatchet->newKey ? ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG : ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG; + if (!m_NextSendRatchet->keyID) v[offset] |= ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG; // for first key only + offset++; // flag + htobe16buf (v.data () + offset, m_NextSendRatchet->keyID); offset += 2; // keyid + if (m_NextSendRatchet->newKey) + { + memcpy (v.data () + offset, m_NextSendRatchet->key.GetPublicKey (), 32); + offset += 32; // public key + } + } // padding v[offset] = eECIESx25519BlkPadding; offset++; htobe16buf (v.data () + offset, paddingSize); offset += 2; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 963429ed..0a051810 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -73,6 +73,7 @@ namespace garlic const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second of inactivity we should restart after const int ECIESX25519_EXPIRATION_TIMEOUT = 600; // in seconds + const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 60000; // number of tags we request new tagset after class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this { @@ -90,7 +91,7 @@ namespace garlic int keyID = 0; i2p::crypto::X25519Keys key; uint8_t remote[32]; // last remote public key - bool newKey; + bool newKey = true; }; public: @@ -136,6 +137,7 @@ namespace garlic size_t CreateDeliveryStatusClove (std::shared_ptr msg, uint8_t * buf, size_t len); void GenerateMoreReceiveTags (std::shared_ptr receiveTagset, int numTags); + void NewNextSendRatchet (); private: @@ -148,9 +150,8 @@ namespace garlic std::shared_ptr m_SendTagset; std::unique_ptr m_Destination;// TODO: might not need it std::list > m_AckRequests; // (tagsetid, index) - int m_SendKeyID = 0, m_ReceiveKeyID = 0; - bool m_SendReverseKey = false; - std::unique_ptr m_NextReceiveRatchet; + bool m_SendReverseKey = false, m_SendForwardKey = false; + std::unique_ptr m_NextReceiveRatchet, m_NextSendRatchet; }; std::shared_ptr WrapECIESX25519AEADRatchetMessage (std::shared_ptr msg, const uint8_t * key, uint64_t tag);