From dd58b2f8672116622713b8736c01e7d7e41250ff Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Mar 2025 15:41:12 -0400 Subject: [PATCH] Post-Quantum. MLDSA44 verifier --- libi2pd/Crypto.h | 3 +++ libi2pd/Identity.cpp | 26 ++++++++++++++++++++++++++ libi2pd/Identity.h | 7 +++++-- libi2pd/Signature.cpp | 34 ++++++++++++++++++++++++++++++++++ libi2pd/Signature.h | 24 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 051f214f..b2fa0292 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -33,6 +33,9 @@ # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif +# if (OPENSSL_VERSION_NUMBER >= 0x030500000) // 3.5.0 +# define OPENSSL_PQ 1 +# endif #endif namespace i2p diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 285bde54..50d5c9c5 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -119,6 +119,16 @@ namespace data memcpy (m_StandardIdentity.signingKey, signingKey, i2p::crypto::GOSTR3410_512_PUBLIC_KEY_LENGTH); break; } +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + { + memcpy (m_StandardIdentity, signingKey, 384); + excessLen = i2p::crypto::MLDSA44_PUBLIC_KEY_LENGTH - 384; + excessBuf = new uint8_t[excessLen]; + memcpy (excessBuf, signingKey + 384, excessLen); + break; + } +#endif default: LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported"); } @@ -352,6 +362,10 @@ namespace data return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512); case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: return new i2p::crypto::RedDSA25519Verifier (); +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + return new i2p::crypto::MLDSA44Verifier (); +#endif case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: @@ -373,6 +387,18 @@ namespace data auto keyLen = verifier->GetPublicKeyLen (); if (keyLen <= 128) verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen); +#if OPENSSL_PQ + else if (keyLen > 384) + { + // for post-quantum + uint8_t * signingKey = new uint8_t[keyLen]; + memcpy (signingKey, m_StandardIdentity.signingKey, 384); + size_t excessLen = keyLen - 384; + memcpy (signingKey + 384, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types + verifier->SetPublicKey (signingKey); + delete[] signingKey; + } +#endif else { // for P521 diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index b5083e7e..cf1dbfcd 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -55,6 +55,8 @@ namespace data Identity& operator=(const Keys& keys); size_t FromBuffer (const uint8_t * buf, size_t len); IdentHash Hash () const; + operator uint8_t * () { return reinterpret_cast(this); } + operator const uint8_t * () const { return reinterpret_cast(this); } }; Keys CreateRandomKeys (); @@ -77,7 +79,8 @@ namespace data const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9; const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB const uint16_t SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 = 11; // for LeaseSet2 only - + const uint16_t SIGNING_KEY_TYPE_MLDSA44 = 15; + typedef uint16_t SigningKeyType; typedef uint16_t CryptoKeyType; @@ -132,7 +135,7 @@ namespace data IdentHash m_IdentHash; std::unique_ptr m_Verifier; size_t m_ExtendedLen; - uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; + uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; // TODO: support PQ keys }; size_t GetIdentityBufferLen (const uint8_t * buf, size_t len); // return actual identity length in buffer diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index d9fa0248..1ad4d2cb 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -199,6 +199,40 @@ namespace crypto else LogPrint (eLogError, "EdDSA signing key is not set"); } +#endif + +#if OPENSSL_PQ + MLDSA44Verifier::MLDSA44Verifier (): + m_Pkey (nullptr) + { + } + + MLDSA44Verifier::~MLDSA44Verifier () + { + EVP_PKEY_free (m_Pkey); + } + + void MLDSA44Verifier::SetPublicKey (const uint8_t * signingKey) + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ML_DSA_44, NULL, signingKey, GetPublicKeyLen ()); + } + + bool MLDSA44Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const + { + if (m_Pkey) + { + EVP_MD_CTX * ctx = EVP_MD_CTX_create (); + EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey); + auto ret = EVP_DigestVerify (ctx, signature, GetSignatureLen (), buf, len); + EVP_MD_CTX_destroy (ctx); + return ret; + } + else + LogPrint (eLogError, "MLDSA44 verification key is not set"); + return false; + } + #endif } } diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 2a731703..3cc7e9c0 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -560,6 +560,30 @@ namespace crypto RedDSA25519Signer signer (signingPrivateKey); memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); } + +#if OPENSSL_PQ + + // Post-Quantum + const size_t MLDSA44_PUBLIC_KEY_LENGTH = 1312; + const size_t MLDSA44_SIGNATURE_LENGTH = 2420; + class MLDSA44Verifier: public Verifier + { + public: + + MLDSA44Verifier (); + void SetPublicKey (const uint8_t * signingKey); + ~MLDSA44Verifier (); + + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; + + size_t GetPublicKeyLen () const { return MLDSA44_PUBLIC_KEY_LENGTH; }; + size_t GetSignatureLen () const { return MLDSA44_SIGNATURE_LENGTH; }; + + private: + + EVP_PKEY * m_Pkey; + }; +#endif } }