1
0
mirror of https://github.com/PurpleI2P/i2pd.git synced 2025-08-26 12:51:54 +00:00

handle multiple ECIESx25519 encryption keys

This commit is contained in:
orignal 2025-07-16 22:05:42 -04:00
parent edc27d5bcb
commit 3a18e7ab91
2 changed files with 68 additions and 36 deletions

View File

@ -28,8 +28,7 @@ namespace client
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, bool isSameThread, std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, bool isSameThread,
const std::map<std::string, std::string>& params): const std::map<std::string, std::string>& params):
LeaseSetDestination (service, isPublic, &params), LeaseSetDestination (service, isPublic, &params),
m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()), m_Owner (owner), m_Identity (identity), m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread),
m_IsCreatingLeaseSet (false), m_IsSameThread (isSameThread),
m_LeaseSetCreationTimer (service), m_ReadinessCheckTimer (service) m_LeaseSetCreationTimer (service), m_ReadinessCheckTimer (service)
{ {
} }
@ -42,26 +41,59 @@ namespace client
m_Owner = nullptr; m_Owner = nullptr;
} }
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) void I2CPDestination::SetEncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key)
{ {
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key); bool exist = false;
auto it = m_EncryptionKeys.find (keyType);
if (it != m_EncryptionKeys.end () && !memcmp (it->second->priv.data (), key, it->second->priv.size ())) // new key?
exist = true;
if (!exist)
{
auto encryptionKey = std::make_shared<i2p::crypto::LocalEncryptionKey> (keyType);
memcpy (encryptionKey->priv.data (), key, encryptionKey->priv.size ());
encryptionKey->CreateDecryptor (); // from private key
m_EncryptionKeys.insert_or_assign (keyType, encryptionKey);
}
} }
void I2CPDestination::SetECIESx25519EncryptionPrivateKey (const uint8_t * key) void I2CPDestination::SetECIESx25519EncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key)
{ {
if (!m_ECIESx25519Decryptor || memcmp (m_ECIESx25519PrivateKey, key, 32)) // new key? bool exist = false;
auto it = m_EncryptionKeys.find (keyType);
if (it != m_EncryptionKeys.end () && !memcmp (it->second->priv.data (), key, it->second->priv.size ())) // new key?
exist = true;
if (!exist)
{ {
m_ECIESx25519Decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate public auto encryptionKey = std::make_shared<i2p::crypto::LocalEncryptionKey> (keyType);
memcpy (m_ECIESx25519PrivateKey, key, 32); memcpy (encryptionKey->priv.data (), key, encryptionKey->priv.size ());
// create decryptor manually
auto decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate publicKey
encryptionKey->decryptor = decryptor;
// assign public key from decryptor
memcpy (encryptionKey->pub.data (), decryptor->GetPubicKey (), encryptionKey->pub.size ());
// insert or replace new
m_EncryptionKeys.insert_or_assign (keyType, encryptionKey);
} }
} }
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const
{ {
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) std::shared_ptr<i2p::crypto::LocalEncryptionKey> encryptionKey;
return m_ECIESx25519Decryptor->Decrypt (encrypted, data); if (!m_EncryptionKeys.empty ())
if (m_Decryptor) {
return m_Decryptor->Decrypt (encrypted, data); if (m_EncryptionKeys.rbegin ()->first == preferredCrypto)
encryptionKey = m_EncryptionKeys.rbegin ()->second;
else
{
auto it = m_EncryptionKeys.find (preferredCrypto);
if (it != m_EncryptionKeys.end ())
encryptionKey = it->second;
}
if (!encryptionKey)
encryptionKey = m_EncryptionKeys.rbegin ()->second;
}
if (encryptionKey)
return encryptionKey->decryptor->Decrypt (encrypted, data);
else else
LogPrint (eLogError, "I2CP: Decryptor is not set"); LogPrint (eLogError, "I2CP: Decryptor is not set");
return false; return false;
@ -69,22 +101,32 @@ namespace client
const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
{ {
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) auto it = m_EncryptionKeys.find (keyType);
return m_ECIESx25519Decryptor->GetPubicKey (); if (it != m_EncryptionKeys.end ())
return it->second->pub.data ();
return nullptr; return nullptr;
} }
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
{ {
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType; #if __cplusplus >= 202002L // C++20
return m_EncryptionKeys.contains (keyType);
#else
return m_EncryptionKeys.count (keyType) > 0;
#endif
} }
i2p::data::CryptoKeyType I2CPDestination::GetPreferredCryptoType () const i2p::data::CryptoKeyType I2CPDestination::GetPreferredCryptoType () const
{ {
if (m_ECIESx25519Decryptor) return !m_EncryptionKeys.empty () ? m_EncryptionKeys.rbegin ()->first : 0;
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
} }
i2p::data::CryptoKeyType I2CPDestination::GetRatchetsHighestCryptoType () const
{
if (m_EncryptionKeys.empty ()) return 0;
auto cryptoType = m_EncryptionKeys.rbegin ()->first;
return cryptoType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? cryptoType : 0;
}
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len, void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len,
i2p::garlic::ECIESX25519AEADRatchetSession * from) i2p::garlic::ECIESX25519AEADRatchetSession * from)
@ -813,7 +855,7 @@ namespace client
// we always assume this field as 20 bytes (DSA) regardless actual size // we always assume this field as 20 bytes (DSA) regardless actual size
// instead of // instead of
//offset += m_Destination->GetIdentity ()->GetSigningPrivateKeyLen (); //offset += m_Destination->GetIdentity ()->GetSigningPrivateKeyLen ();
m_Destination->SetEncryptionPrivateKey (buf + offset); m_Destination->SetEncryptionPrivateKey (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, buf + offset);
offset += 256; offset += 256;
m_Destination->LeaseSetCreated (buf + offset, len - offset); m_Destination->LeaseSetCreated (buf + offset, len - offset);
} }
@ -846,13 +888,10 @@ namespace client
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
if (offset + keyLen > len) return; if (offset + keyLen > len) return;
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (keyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset); m_Destination->SetECIESx25519EncryptionPrivateKey (keyType, buf + offset);
else else
{ m_Destination->SetEncryptionPrivateKey (keyType, buf + offset); // from identity
m_Destination->SetEncryptionType (keyType);
m_Destination->SetEncryptionPrivateKey (buf + offset);
}
offset += keyLen; offset += keyLen;
} }

View File

@ -92,9 +92,8 @@ namespace client
void Stop () override; void Stop () override;
void SetEncryptionPrivateKey (const uint8_t * key); void SetEncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key);
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; }; void SetECIESx25519EncryptionPrivateKey (i2p::data::CryptoKeyType keyType, const uint8_t * key);
void SetECIESx25519EncryptionPrivateKey (const uint8_t * key);
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
@ -109,10 +108,7 @@ namespace client
protected: protected:
// GarlicDestination // GarlicDestination
i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const override i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const override;
{
return m_ECIESx25519Decryptor ? i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD : 0;
}
// LeaseSetDestination // LeaseSetDestination
void CleanupDestination () override; void CleanupDestination () override;
i2p::data::CryptoKeyType GetPreferredCryptoType () const override; i2p::data::CryptoKeyType GetPreferredCryptoType () const override;
@ -134,10 +130,7 @@ namespace client
std::shared_ptr<I2CPSession> m_Owner; std::shared_ptr<I2CPSession> m_Owner;
std::shared_ptr<const i2p::data::IdentityEx> m_Identity; std::shared_ptr<const i2p::data::IdentityEx> m_Identity;
i2p::data::CryptoKeyType m_EncryptionKeyType; std::map<i2p::data::CryptoKeyType, std::shared_ptr<i2p::crypto::LocalEncryptionKey> > m_EncryptionKeys; // last is most preferable
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor; // standard
std::shared_ptr<i2p::crypto::ECIESX25519AEADRatchetDecryptor> m_ECIESx25519Decryptor;
uint8_t m_ECIESx25519PrivateKey[32];
uint64_t m_LeaseSetExpirationTime; uint64_t m_LeaseSetExpirationTime;
bool m_IsCreatingLeaseSet, m_IsSameThread; bool m_IsCreatingLeaseSet, m_IsSameThread;
boost::asio::deadline_timer m_LeaseSetCreationTimer, m_ReadinessCheckTimer; boost::asio::deadline_timer m_LeaseSetCreationTimer, m_ReadinessCheckTimer;