From e3227ee5ee79772cb390b390366777e6723af0b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 13 Mar 2025 15:43:22 -0400 Subject: [PATCH] MLDSA44 signer and keygen --- libi2pd/Identity.cpp | 10 +++++ libi2pd/Signature.cpp | 99 +++++++++++++++++++++++++++++++++++++++---- libi2pd/Signature.h | 27 ++++++++++++ 3 files changed, 128 insertions(+), 8 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 50d5c9c5..93d7ec08 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -652,6 +652,11 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: return new i2p::crypto::RedDSA25519Signer (priv); break; +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + return new i2p::crypto::MLDSA44Signer (priv); + break; +#endif default: LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported"); } @@ -757,6 +762,11 @@ namespace data case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: i2p::crypto::CreateRedDSA25519RandomKeys (priv, pub); break; +#if OPENSSL_PQ + case SIGNING_KEY_TYPE_MLDSA44: + i2p::crypto::CreateMLDSA44RandomKeys (priv, pub); + break; +#endif default: LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1 diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 1ad4d2cb..1c19c907 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -202,6 +202,14 @@ namespace crypto #endif #if OPENSSL_PQ +#include + + static const OSSL_PARAM MLDSAParams[] = + { + OSSL_PARAM_octet_string("context-string", (unsigned char *)"A context string", 16), + OSSL_PARAM_END + }; + MLDSA44Verifier::MLDSA44Verifier (): m_Pkey (nullptr) { @@ -214,24 +222,99 @@ namespace crypto 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 ()); + if (m_Pkey) + { + EVP_PKEY_free (m_Pkey); + m_Pkey = nullptr; + } + OSSL_PARAM params[] = + { + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PUB_KEY, (uint8_t *)signingKey, GetPublicKeyLen ()), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-DSA-44", NULL); + if (ctx) + { + EVP_PKEY_fromdata_init (ctx); + EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, params); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLDSA44 can't create PKEY context"); } bool MLDSA44Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { + bool ret = false; 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; + EVP_PKEY_CTX * vctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (vctx) + { + EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); + if (sig) + { + EVP_PKEY_verify_message_init (vctx, sig, MLDSAParams); + ret = EVP_PKEY_verify (vctx, signature, GetSignatureLen (), buf, len); + EVP_SIGNATURE_free (sig); + } + EVP_PKEY_CTX_free (vctx); + } + else + LogPrint (eLogError, "MLDSA44 can't obtain context from PKEY"); } else LogPrint (eLogError, "MLDSA44 verification key is not set"); - return false; + return ret; } + + MLDSA44Signer::MLDSA44Signer (const uint8_t * signingPrivateKey): + m_Pkey (nullptr) + { + OSSL_PARAM params[] = + { + OSSL_PARAM_octet_string (OSSL_PKEY_PARAM_PRIV_KEY, (uint8_t *)signingPrivateKey, MLDSA44_PRIVATE_KEY_LENGTH), + OSSL_PARAM_END + }; + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "ML-DSA-44", NULL); + if (ctx) + { + EVP_PKEY_fromdata_init (ctx); + EVP_PKEY_fromdata (ctx, &m_Pkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, params); + EVP_PKEY_CTX_free (ctx); + } + else + LogPrint (eLogError, "MLDSA44 can't create PKEY context"); + } + + MLDSA44Signer::~MLDSA44Signer () + { + if (m_Pkey) EVP_PKEY_free (m_Pkey); + } + + void MLDSA44Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + if (m_Pkey) + { + EVP_PKEY_CTX * sctx = EVP_PKEY_CTX_new_from_pkey (NULL, m_Pkey, NULL); + if (sctx) + { + EVP_SIGNATURE * sig = EVP_SIGNATURE_fetch (NULL, "ML-DSA-44", NULL); + if (sig) + { + EVP_PKEY_sign_message_init (sctx, sig, MLDSAParams); + size_t siglen = MLDSA44_SIGNATURE_LENGTH; + EVP_PKEY_sign (sctx, signature, &siglen, buf, len); + EVP_SIGNATURE_free (sig); + } + EVP_PKEY_CTX_free (sctx); + } + else + LogPrint (eLogError, "MLDSA44 can't obtain context from PKEY"); + } + else + LogPrint (eLogError, "MLDSA44 signing key is not set"); + } #endif } diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 3cc7e9c0..c77e10dd 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -562,10 +562,12 @@ namespace crypto } #if OPENSSL_PQ +#include // Post-Quantum const size_t MLDSA44_PUBLIC_KEY_LENGTH = 1312; const size_t MLDSA44_SIGNATURE_LENGTH = 2420; + const size_t MLDSA44_PRIVATE_KEY_LENGTH = 2560; class MLDSA44Verifier: public Verifier { public: @@ -578,11 +580,36 @@ namespace crypto size_t GetPublicKeyLen () const { return MLDSA44_PUBLIC_KEY_LENGTH; }; size_t GetSignatureLen () const { return MLDSA44_SIGNATURE_LENGTH; }; + size_t GetPrivateKeyLen () const { return MLDSA44_PRIVATE_KEY_LENGTH; }; private: EVP_PKEY * m_Pkey; }; + + class MLDSA44Signer: public Signer + { + public: + + MLDSA44Signer (const uint8_t * signingPrivateKey); + ~MLDSA44Signer (); + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + + private: + + EVP_PKEY * m_Pkey; + }; + + inline void CreateMLDSA44RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + EVP_PKEY * pkey = EVP_PKEY_Q_keygen (NULL, NULL, "ML-DSA-44"); + size_t len = MLDSA44_PUBLIC_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (pkey, OSSL_PKEY_PARAM_PUB_KEY, signingPublicKey, MLDSA44_PUBLIC_KEY_LENGTH, &len); + len = MLDSA44_PRIVATE_KEY_LENGTH; + EVP_PKEY_get_octet_string_param (pkey, OSSL_PKEY_PARAM_PRIV_KEY, signingPrivateKey, MLDSA44_PRIVATE_KEY_LENGTH, &len); + EVP_PKEY_free (pkey); + } #endif } }