diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 3e6279ff..68850a9d 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -351,11 +351,13 @@ namespace crypto #endif } - void X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) + bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) { + if (pub[31] & 0x80) return false; // not x25519 key #if OPENSSL_X25519 EVP_PKEY_derive_init (m_Ctx); auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32); + if (!pkey) return false; EVP_PKEY_derive_set_peer (m_Ctx, pkey); size_t len = 32; EVP_PKEY_derive (m_Ctx, shared, &len); @@ -363,6 +365,7 @@ namespace crypto #else GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx); #endif + return true; } void X25519Keys::GetPrivateKey (uint8_t * priv) const diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index c63cc45e..a6c64c70 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -89,7 +89,7 @@ namespace crypto const uint8_t * GetPublicKey () const { return m_PublicKey; }; void GetPrivateKey (uint8_t * priv) const; void SetPrivateKey (const uint8_t * priv, bool calculatePublic = false); - void Agree (const uint8_t * pub, uint8_t * shared); + bool Agree (const uint8_t * pub, uint8_t * shared); bool IsElligatorIneligible () const { return m_IsElligatorIneligible; } void SetElligatorIneligible () { m_IsElligatorIneligible = true; } diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index 4518a347..ad93d386 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -173,8 +173,7 @@ namespace crypto bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding) { - m_StaticKeys.Agree (epub, sharedSecret); - return true; + return m_StaticKeys.Agree (epub, sharedSecret); } void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index d2286b15..cbf5175a 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -231,7 +231,11 @@ namespace garlic MixHash (m_Aepk, 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; - GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, aepk) + if (!GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); + return false; + } MixKey (sharedSecret); // decrypt flags/static @@ -251,7 +255,11 @@ namespace garlic { // static key, fs is apk memcpy (m_RemoteStaticKey, fs, 32); - GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, apk) + if (!GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, apk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); + return false; + } MixKey (sharedSecret); } else // all zeros flags @@ -448,7 +456,11 @@ namespace garlic i2p::crypto::InitNoiseIKState (*this, m_RemoteStaticKey); // bpk MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; - m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) + if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // x25519(aesk, bpk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); + return false; + } MixKey (sharedSecret); // encrypt flags/static key section uint8_t nonce[12]; @@ -504,7 +516,11 @@ namespace garlic MixHash (out + offset, 32); // h = SHA256(h || aepk) offset += 32; uint8_t sharedSecret[32]; - m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) + if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // x25519(aesk, bpk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); + return false; + } MixKey (sharedSecret); uint8_t nonce[12]; CreateNonce (0, nonce); @@ -540,9 +556,17 @@ namespace garlic MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; - m_EphemeralKeys->Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk) + if (!m_EphemeralKeys->Agree (m_Aepk, sharedSecret)) // sharedSecret = x25519(besk, aepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); + return false; + } MixKey (sharedSecret); - m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk) + if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); + return false; + } MixKey (sharedSecret); uint8_t nonce[12]; CreateNonce (0, nonce); @@ -624,7 +648,11 @@ namespace garlic MixHash (tag, 8); // h = SHA256(h || tag) MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; - m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) + if (!m_EphemeralKeys->Agree (bepk, sharedSecret)) // sharedSecret = x25519(aesk, bepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key"); + return false; + } MixKey (sharedSecret); GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) MixKey (sharedSecret); @@ -788,7 +816,11 @@ namespace garlic i2p::crypto::InitNoiseNState (*this, GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk MixHash (buf, 32); uint8_t sharedSecret[32]; - GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, aepk) + if (!GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk) + { + LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); + return false; + } MixKey (sharedSecret); buf += 32; len -= 32; uint8_t nonce[12]; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index aff92837..6f9a37b9 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -866,6 +866,7 @@ namespace garlic { it->second.tagset->DeleteSymmKey (it->second.index); it = m_ECIESx25519Tags.erase (it); + numExpiredTags++; } else ++it; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d258b341..ce1eede0 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -729,7 +729,11 @@ namespace i2p m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; - m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false); + if (!m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false)) + { + LogPrint (eLogWarning, "Router: Incorrect ephemeral public key"); + return false; + } m_CurrentNoiseState->MixKey (sharedSecret); encrypted += 32; uint8_t nonce[12];