handle any incoming post quantum crypto type

This commit is contained in:
orignal 2025-04-17 22:15:17 -04:00
parent 67fe6faf2d
commit bbfe81cb79
6 changed files with 41 additions and 43 deletions

View file

@ -1556,11 +1556,12 @@ namespace client
#endif #endif
} }
bool ClientDestination::SupportsRatchets () const i2p::data::CryptoKeyType ClientDestination::GetRatchetsHighestCryptoType () const
{ {
if (m_EncryptionKeys.empty ()) return false; if (m_EncryptionKeys.empty ()) return 0;
return m_EncryptionKeys.rbegin ()->first >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; auto cryptoType = m_EncryptionKeys.rbegin ()->first;
} return cryptoType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? cryptoType : 0;
}
const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
{ {

View file

@ -283,7 +283,7 @@ namespace client
protected: protected:
// GarlicDestionation // GarlicDestionation
bool SupportsRatchets () const override; i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const override;
// LeaseSetDestination // LeaseSetDestination
void CleanupDestination () override; void CleanupDestination () override;
i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; } i2p::data::CryptoKeyType GetPreferredCryptoType () const override { return m_PreferredCryptoType; }

View file

@ -266,40 +266,40 @@ namespace garlic
} }
buf += 32; len -= 32; buf += 32; len -= 32;
uint64_t n = 0;
uint8_t sharedSecret[32]; uint8_t sharedSecret[32];
bool decrypted = false; bool decrypted = false;
auto cryptoType = GetOwner ()->GetRatchetsHighestCryptoType ();
#if OPENSSL_PQ #if OPENSSL_PQ
if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) if (cryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // we support post quantum
{ {
i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, i2p::crypto::InitNoiseIKStateMLKEM (GetNoiseState (), cryptoType, GetOwner ()->GetEncryptionPublicKey (cryptoType)); // bpk
GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)); // bpk
MixHash (m_Aepk, 32); // h = SHA256(h || aepk) MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)) // x25519(bsk, aepk) if (GetOwner ()->Decrypt (m_Aepk, sharedSecret, cryptoType)) // x25519(bsk, aepk)
{ {
MixKey (sharedSecret); MixKey (sharedSecret);
uint8_t nonce[12], encapsKey[i2p::crypto::MLKEM512_KEY_LENGTH]; auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (cryptoType);
CreateNonce (n, nonce); std::vector<uint8_t> encapsKey(keyLen);
if (Decrypt (buf, encapsKey, i2p::crypto::MLKEM512_KEY_LENGTH)) if (Decrypt (buf, encapsKey.data (), keyLen))
{ {
decrypted = true; // encaps section has right hash decrypted = true; // encaps section has right hash
MixHash (buf, i2p::crypto::MLKEM512_KEY_LENGTH + 16); MixHash (buf, keyLen + 16);
buf += i2p::crypto::MLKEM512_KEY_LENGTH + 16; buf += keyLen + 16;
len -= i2p::crypto::MLKEM512_KEY_LENGTH + 16; len -= keyLen + 16;
n++;
m_PQKeys = i2p::crypto::CreateMLKEMKeys (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD); m_PQKeys = i2p::crypto::CreateMLKEMKeys (cryptoType);
m_PQKeys->SetPublicKey (encapsKey); m_PQKeys->SetPublicKey (encapsKey.data ());
} }
} }
} }
#endif #endif
if (!decrypted) if (!decrypted)
{ {
if (GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) if (cryptoType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ||
GetOwner ()->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
{ {
cryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk
MixHash (m_Aepk, 32); // h = SHA256(h || aepk) MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
@ -318,8 +318,7 @@ namespace garlic
} }
// decrypt flags/static // decrypt flags/static
uint8_t nonce[12], fs[32]; uint8_t fs[32];
CreateNonce (n, nonce);
if (!Decrypt (buf, fs, 32)) if (!Decrypt (buf, fs, 32))
{ {
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed ");
@ -332,16 +331,8 @@ namespace garlic
bool isStatic = !i2p::data::Tag<32> (fs).IsZero (); bool isStatic = !i2p::data::Tag<32> (fs).IsZero ();
if (isStatic) if (isStatic)
{ {
// static key, fs is apk // static key, fs is apk
#if OPENSSL_PQ SetRemoteStaticKey (cryptoType, fs);
if (m_PQKeys)
{
SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD, fs);
CreateNonce (0, nonce); // reset nonce
}
else
#endif
SetRemoteStaticKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD, fs);
if (!GetOwner ()->Decrypt (fs, sharedSecret, m_RemoteStaticKeyType)) // x25519(bsk, apk) if (!GetOwner ()->Decrypt (fs, sharedSecret, m_RemoteStaticKeyType)) // x25519(bsk, apk)
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
@ -349,8 +340,6 @@ namespace garlic
} }
MixKey (sharedSecret); MixKey (sharedSecret);
} }
else // all zeros flags
CreateNonce (1, nonce);
// decrypt payload // decrypt payload
std::vector<uint8_t> payload (len - 16); // we must save original ciphertext std::vector<uint8_t> payload (len - 16); // we must save original ciphertext
@ -966,7 +955,8 @@ namespace garlic
size_t len = CreatePayload (msg, m_State != eSessionStateEstablished, payload); size_t len = CreatePayload (msg, m_State != eSessionStateEstablished, payload);
if (!len) return nullptr; if (!len) return nullptr;
#if OPENSSL_PQ #if OPENSSL_PQ
auto m = NewI2NPMessage (len + (m_State == eSessionStateEstablished ? 28 : i2p::crypto::MLKEM512_KEY_LENGTH + 116)); auto m = NewI2NPMessage (len + (m_State == eSessionStateEstablished ? 28 :
i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 116));
#else #else
auto m = NewI2NPMessage (len + 100); // 96 + 4 auto m = NewI2NPMessage (len + 100); // 96 + 4
#endif #endif
@ -994,8 +984,8 @@ namespace garlic
return nullptr; return nullptr;
len += 72; len += 72;
#if OPENSSL_PQ #if OPENSSL_PQ
if (m_RemoteStaticKeyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD) if (m_RemoteStaticKeyType >= i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD)
len += i2p::crypto::MLKEM512_CIPHER_TEXT_LENGTH + 16; len += i2p::crypto::GetMLKEMPublicKeyLen (m_RemoteStaticKeyType) + 16;
#endif #endif
break; break;
case eSessionStateNewSessionReplySent: case eSessionStateNewSessionReplySent:

View file

@ -498,7 +498,8 @@ namespace garlic
buf += 4; // length buf += 4; // length
bool found = false; bool found = false;
if (SupportsRatchets ()) bool supportsRatchets = SupportsRatchets ();
if (supportsRatchets)
// try ECIESx25519 tag // try ECIESx25519 tag
found = HandleECIESx25519TagMessage (buf, length); found = HandleECIESx25519TagMessage (buf, length);
if (!found) if (!found)
@ -535,7 +536,7 @@ namespace garlic
decryption->Decrypt(buf + 514, length - 514, iv, buf + 514); decryption->Decrypt(buf + 514, length - 514, iv, buf + 514);
HandleAESBlock (buf + 514, length - 514, decryption, msg->from); HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
} }
else if (SupportsRatchets ()) else if (supportsRatchets)
{ {
// otherwise ECIESx25519 // otherwise ECIESx25519
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();

View file

@ -266,6 +266,10 @@ namespace garlic
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0; virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
virtual i2p::data::CryptoKeyType GetRatchetsHighestCryptoType () const
{
return GetIdentity ()->GetCryptoKeyType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? GetIdentity ()->GetCryptoKeyType () : 0;
}
protected: protected:
@ -279,11 +283,10 @@ namespace garlic
void SaveTags (); void SaveTags ();
void LoadTags (); void LoadTags ();
virtual bool SupportsRatchets () const { return GetIdentity ()->GetCryptoKeyType () >= i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }
private: private:
bool SupportsRatchets () const { return GetRatchetsHighestCryptoType () > 0; }
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from); std::shared_ptr<i2p::tunnel::InboundTunnel> from);
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);

View file

@ -109,7 +109,10 @@ namespace client
protected: protected:
// GarlicDestination // GarlicDestination
bool SupportsRatchets () const override { return (bool)m_ECIESx25519Decryptor; } 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;