diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 06f6c84e..43049d56 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -386,7 +386,8 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Bob - uint64_t tag = CreateNewSessionTagset ()->GetNextSessionTag (); + m_NSRTagset = CreateNewSessionTagset (); + uint64_t tag = m_NSRTagset->GetNextSessionTag (); size_t offset = 0; memcpy (out + offset, &tag, 8); @@ -396,6 +397,8 @@ namespace garlic LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; } + memcpy (m_NSREncodedKey, out + offset, 56); // for possible next NSR + memcpy (m_NSRH, m_H, 32); offset += 32; // KDF for Reply Key Section MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) @@ -408,14 +411,13 @@ namespace garlic uint8_t nonce[12]; CreateNonce (0, nonce); // calulate hash for zero length - if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) + if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); return false; } MixHash (out + offset, 16); // h = SHA256(h || ciphertext) offset += 16; - memcpy (m_NSRHeader, out, 56); // for possible next NSR // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) @@ -442,9 +444,21 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Bob and sent NSR already - memcpy (out, m_NSRHeader, 56); + uint64_t tag = m_NSRTagset->GetNextSessionTag (); // next tag + memcpy (out, &tag, 8); + memcpy (out + 8, m_NSREncodedKey, 32); + // recalculte h with new tag + memcpy (m_H, m_NSRH, 32); + MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) + MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t nonce[12]; - CreateNonce (0, nonce); + CreateNonce (0, nonce); + if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + 40, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) + { + LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); + return false; + } + MixHash (out + 40, 16); // h = SHA256(h || ciphertext) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt { @@ -568,6 +582,7 @@ namespace garlic { case eSessionStateNewSessionReplySent: m_State = eSessionStateEstablished; + m_NSRTagset = nullptr; #if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; #endif diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 20676405..995bbe4a 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -147,11 +147,11 @@ namespace garlic uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only - uint8_t m_NSRHeader[56], m_NSRKey[32]; // new session reply, for incoming only + uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; uint64_t m_LastActivityTimestamp = 0; // incoming - std::shared_ptr m_SendTagset; + std::shared_ptr m_SendTagset, m_NSRTagset; std::unique_ptr m_Destination;// TODO: might not need it std::list > m_AckRequests; // (tagsetid, index) bool m_SendReverseKey = false, m_SendForwardKey = false;