Merge pull request #11424 from Frauschi/ed448-make-public-store-pub

Ed448 pub key fix
pull/11439/head
JacobBarthelmeh 2026-09-11 09:55:26 -06:00 committed by GitHub
commit 1e46e2fc65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 139 additions and 22 deletions

View File

@ -1,14 +1,14 @@
/*!
\ingroup ED25519
\brief ed25519_keyEd25519pubKey
\brief ed25519_keyEd25519pubKey使
\return 0
\return BAD_FUNC_ARG keypubKeyNULL32Ed2551932
\return ECC_PRIV_KEY_E ed25519_key
\return MEMORY_E
\param [in] key ed25519_key
\param [in,out] key ed25519_key
\param [out] pubKey
\param [in] pubKeySz ED25519_PUB_KEY_SIZE
@ -23,7 +23,7 @@
wc_ed25519_init(&key);
wc_ed25519_import_private_only(priv, sizeof(priv), &key);
ret = wc_ed25519_make_public(&key, pub, &pubSz);
ret = wc_ed25519_make_public(&key, pub, pubSz);
if (ret != 0) {
// 公開鍵の作成エラー
}

View File

@ -1,13 +1,13 @@
/*!
\ingroup ED448
\brief Ed448pubKeypubKeySz
\brief Ed448pubKeypubKeySz使
\return 0
\return BAD_FUNC_ARG keypubKeyNULL57Ed44857
\return MEMORY_E
\param [in] key ed448_key
\param [in,out] key ed448_key
\param [out] pubKey
\param [in] pubKeySz pubKey()
@ -22,7 +22,7 @@
wc_ed448_init(&key);
wc_ed448_import_private_only(priv, sizeof(priv), &key);
ret = wc_ed448_make_public(&key, pub, &pubSz);
ret = wc_ed448_make_public(&key, pub, pubSz);
if (ret != 0) {
// 公開鍵の作成エラー
}

View File

@ -3,7 +3,8 @@
\brief This function generates the Ed25519 public key from the private key,
stored in the ed25519_key object. It stores the public key in the buffer
pubKey.
pubKey. If the key object does not already carry a public key, the derived
key is also stored in it, so that the key can be used for signing.
\return 0 Returned upon successfully making the public key.
\return BAD_FUNC_ARG Returned if key or pubKey evaluate to NULL, or if the
@ -13,7 +14,7 @@
\return MEMORY_E Returned if there is an error allocating memory
during function execution.
\param [in] key Pointer to the ed25519_key for which to generate a key.
\param [in,out] key Pointer to the ed25519_key for which to generate a key.
\param [out] pubKey Pointer to the buffer in which to store the public key.
\param [in] pubKeySz Size of the public key. Should be ED25519_PUB_KEY_SIZE.
@ -28,7 +29,7 @@
wc_ed25519_init(&key);
wc_ed25519_import_private_only(priv, sizeof(priv), &key);
ret = wc_ed25519_make_public(&key, pub, &pubSz);
ret = wc_ed25519_make_public(&key, pub, pubSz);
if (ret != 0) {
// error making public key
}

View File

@ -3,7 +3,9 @@
\brief This function generates the Ed448 public key from the private key.
It stores the public key in the buffer pubKey, and sets the bytes
written to this buffer in pubKeySz.
written to this buffer in pubKeySz. If the key object does not already
carry a public key, the derived key is also stored in it, so that the key
can be used for signing.
\return 0 Returned upon successfully making the public key.
\return BAD_FUNC_ARG Returned ifi key or pubKey evaluate to NULL, or if the
@ -11,7 +13,7 @@
\return MEMORY_E Returned if there is an error allocating memory
during function execution.
\param [in] key Pointer to the ed448_key for which to generate a key.
\param [in,out] key Pointer to the ed448_key for which to generate a key.
\param [out] pubKey Pointer to the buffer in which to store the public key.
\param [in] pubKeySz Size of the pubKey buffer in bytes.
@ -26,7 +28,7 @@
wc_ed448_init(&key);
wc_ed448_import_private_only(priv, sizeof(priv), &key);
ret = wc_ed448_make_public(&key, pub, &pubSz);
ret = wc_ed448_make_public(&key, pub, pubSz);
if (ret != 0) {
// error making public key
}

View File

@ -29305,8 +29305,6 @@ static int test_wc_SignCRL_ed25519(void)
/* The key file carries the private key only, so derive the public key that
* Ed25519 signing needs. */
ExpectIntEQ(wc_ed25519_make_public(&key, key.p, ED25519_PUB_KEY_SIZE), 0);
if (EXPECT_SUCCESS())
key.pubKeySet = 1;
if (EXPECT_SUCCESS()) {
ExpectIntEQ(crl_sign_verify_ex2(certDer, (word32)certDerSz,
@ -29348,8 +29346,6 @@ static int test_wc_SignCRL_ed448(void)
/* The key file carries the private key only, so derive the public key that
* Ed448 signing needs. */
ExpectIntEQ(wc_ed448_make_public(&key, key.p, ED448_PUB_KEY_SIZE), 0);
if (EXPECT_SUCCESS())
key.pubKeySet = 1;
if (EXPECT_SUCCESS()) {
ExpectIntEQ(crl_sign_verify_ex2(certDer, (word32)certDerSz,

View File

@ -89,6 +89,95 @@ int test_wc_ed448_make_key(void)
} /* END test_wc_ed448_make_key */
/*
* Testing that wc_ed448_make_public() adopts the derived key into the key
* object when the key arrived without a public half.
*/
int test_wc_ed448_make_public_stores_pub(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT) && \
defined(HAVE_ED448_KEY_EXPORT)
ed448_key key;
ed448_key privOnly;
WC_RNG rng;
byte priv[ED448_KEY_SIZE];
byte pub[ED448_PUB_KEY_SIZE];
byte derived[ED448_PUB_KEY_SIZE];
byte exported[ED448_PRV_KEY_SIZE];
word32 privSz = sizeof(priv);
word32 pubSz = sizeof(pub);
word32 exportedSz = sizeof(exported);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
ed448_key pubOnly;
byte msg[] = "Everybody gets Friday off.\n";
byte sig[ED448_SIG_SIZE];
word32 sigSz = sizeof(sig);
int verify_ok = 0;
#endif
XMEMSET(&key, 0, sizeof(ed448_key));
XMEMSET(&privOnly, 0, sizeof(ed448_key));
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(derived, 0, sizeof(derived));
XMEMSET(exported, 0, sizeof(exported));
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
XMEMSET(&pubOnly, 0, sizeof(ed448_key));
XMEMSET(sig, 0, sizeof(sig));
#endif
ExpectIntEQ(wc_ed448_init(&key), 0);
ExpectIntEQ(wc_ed448_init(&privOnly), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private_only(&key, priv, &privSz), 0);
PRIVATE_KEY_LOCK();
ExpectIntEQ(wc_ed448_export_public(&key, pub, &pubSz), 0);
/* A PKCS#8 v1 PrivateKeyInfo has no public-key field, so this is the
* state a decoded private key arrives in. */
ExpectIntEQ(wc_ed448_import_private_only(priv, privSz, &privOnly), 0);
ExpectIntEQ(wc_ed448_make_public(&privOnly, derived, sizeof(derived)), 0);
ExpectIntEQ(XMEMCMP(derived, pub, ED448_PUB_KEY_SIZE), 0);
/* Setting pubKeySet is not enough: wc_ed448_sign_msg() gates on the flag
* and hashes key->p, so a key left with an empty p signs over zeros. */
ExpectIntEQ(XMEMCMP(privOnly.p, pub, ED448_PUB_KEY_SIZE), 0);
/* wc_ed448_export_private() gates on privKeySet alone and hands back all
* of key->k, so the mirrored public half has to be there too. */
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_ed448_export_private(&privOnly, exported, &exportedSz), 0);
PRIVATE_KEY_LOCK();
ExpectIntEQ(exportedSz, ED448_PRV_KEY_SIZE);
ExpectIntEQ(XMEMCMP(exported, priv, ED448_KEY_SIZE), 0);
ExpectIntEQ(XMEMCMP(exported + ED448_KEY_SIZE, pub, ED448_PUB_KEY_SIZE), 0);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
/* Verify against a key that only ever saw the real public half, so a
* signature made over an empty p cannot verify against itself. */
ExpectIntEQ(wc_ed448_init(&pubOnly), 0);
ExpectIntEQ(wc_ed448_import_public(pub, pubSz, &pubOnly), 0);
ExpectIntEQ(wc_ed448_sign_msg(msg, sizeof(msg), sig, &sigSz, &privOnly,
NULL, 0), 0);
ExpectIntEQ(wc_ed448_verify_msg(sig, sigSz, msg, sizeof(msg), &verify_ok,
&pubOnly, NULL, 0), 0);
ExpectIntEQ(verify_ok, 1);
#endif
DoExpectIntEQ(wc_FreeRng(&rng), 0);
wc_ed448_free(&key);
wc_ed448_free(&privOnly);
#if defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY)
wc_ed448_free(&pubOnly);
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ed448_make_public_stores_pub */
/*
* Testing wc_ed448_init()
*/

View File

@ -25,6 +25,7 @@
#include <tests/api/api_decl.h>
int test_wc_ed448_make_key(void);
int test_wc_ed448_make_public_stores_pub(void);
int test_wc_ed448_init(void);
int test_wc_ed448_sign_msg(void);
int test_wc_ed448_verify_sig_S_range(void);
@ -48,6 +49,7 @@ int test_wc_ed448_cryptocb(void);
#define TEST_ED448_DECLS \
TEST_DECL_GROUP("ed448", test_wc_ed448_make_key), \
TEST_DECL_GROUP("ed448", test_wc_ed448_make_public_stores_pub), \
TEST_DECL_GROUP("ed448", test_wc_ed448_init), \
TEST_DECL_GROUP("ed448", test_wc_ed448_sign_msg), \
TEST_DECL_GROUP("ed448", test_wc_ed448_verify_sig_S_range), \

View File

@ -315,7 +315,24 @@ static int ed448_is_small_order(const byte p[ED448_PUB_KEY_SIZE])
return 0;
}
/* Mirror a derived public key into the key object, in the layout
* wc_ed448_make_key() leaves: key->p, and a copy after the private key in
* key->k. Only ever called for a key with no public half yet - deriving into
* scratch and comparing against key->p is how wc_ed448_check_key() works.
*/
static void ed448_store_public(ed448_key* key, const byte* pubKey)
{
if (pubKey != key->p) {
XMEMCPY(key->p, pubKey, ED448_PUB_KEY_SIZE);
}
/* put public key after private key, on the same buffer */
XMEMMOVE(key->k + ED448_KEY_SIZE, key->p, ED448_PUB_KEY_SIZE);
}
/* Derive the public key for the private key.
*
* Also stores the derived key in the key object when it did not already carry
* a public half.
*
* key [in] Ed448 key object.
* pubKey [in] Byte array to hold the public key.
@ -328,6 +345,7 @@ static int ed448_is_small_order(const byte p[ED448_PUB_KEY_SIZE])
int wc_ed448_make_public(ed448_key* key, unsigned char* pubKey, word32 pubKeySz)
{
int ret = 0;
int storePub = 0;
byte az[ED448_PRV_KEY_SIZE];
ge448_p2 A;
@ -339,6 +357,14 @@ int wc_ed448_make_public(ed448_key* key, unsigned char* pubKey, word32 pubKeySz)
ret = ECC_PRIV_KEY_E;
}
if (ret == 0) {
/* The key doesn't carry its public half yet (e.g. it was decoded from
* a PKCS#8 v1 PrivateKeyInfo, which holds only the seed): fill it in
* as well, so pubKeySet below doesn't end up set on a key whose p/k
* are still empty. */
storePub = !key->pubKeySet;
}
if (ret == 0)
ret = ed448_hash(key, key->k, ED448_KEY_SIZE, az, sizeof(az));
@ -354,6 +380,8 @@ int wc_ed448_make_public(ed448_key* key, unsigned char* pubKey, word32 pubKeySz)
if (ret == 0) {
ge448_to_bytes(pubKey, &A);
if (storePub)
ed448_store_public(key, pubKey);
key->pubKeySet = 1;
}
@ -391,23 +419,22 @@ int wc_ed448_make_key(WC_RNG* rng, int keySz, ed448_key* key)
}
if (ret == 0) {
key->privKeySet = 1;
/* pubKeySet was just cleared, so this also stores the public key in
* key->p and after the private key in key->k */
ret = wc_ed448_make_public(key, key->p, ED448_PUB_KEY_SIZE);
if (ret != 0) {
key->privKeySet = 0;
ForceZero(key->k, ED448_KEY_SIZE);
}
}
#if FIPS_VERSION3_GE(6,0,0)
if (ret == 0) {
/* put public key after private key, on the same buffer */
XMEMMOVE(key->k + ED448_KEY_SIZE, key->p, ED448_PUB_KEY_SIZE);
#if FIPS_VERSION3_GE(6,0,0)
ret = wc_ed448_check_key(key);
if (ret == 0) {
ret = ed448_pairwise_consistency_test(key, rng);
}
#endif
}
#endif
return ret;
}
@ -1401,7 +1428,7 @@ int wc_ed448_import_private_key_ex(const byte* priv, word32 privSz,
}
/* make the private key (priv + pub) */
XMEMCPY(key->k + ED448_KEY_SIZE, key->p, ED448_PUB_KEY_SIZE);
ed448_store_public(key, key->p);
return ret;
}