Add AES-GCM DEM, CryptoCb support, and devId threading to ECIES

Add AES-GCM (128/256) as an ECIES DEM next to the AES-CBC/CTR+HMAC modes. Only the encryption key comes from the KDF; the mac salt is bound as GCM AAD and the 16-byte tag replaces the HMAC. The GCM DEM honors all three IV build modes, and default fixed-nonce GCM is gated behind the new WOLFSSL_ECIES_STATIC_GCM_NONCE opt-in. Adds ECIES CryptoCb encrypt/decrypt, the WOLF_CRYPTO_CB ctx getters, devId/heap threading into the DEM primitives, and test/benchmark/CI coverage.
This commit is contained in:
night1rider
2026-07-10 16:57:24 -06:00
parent e6d86b4bbb
commit c00e7260be
11 changed files with 1595 additions and 92 deletions
+15
View File
@@ -269,6 +269,21 @@ jobs:
{"name": "cryptocb-aesgcm-setkey-free", "minutes": 2.1,
"configure": ["--enable-cryptocb", "--enable-aesgcm",
"CPPFLAGS=-DWOLF_CRYPTO_CB_AES_SETKEY -DWOLF_CRYPTO_CB_FREE"]},
{"name": "ecies-sec1-gcm-static-nonce", "minutes": 2.0,
"comment": "ECIES with the AES-GCM DEM in the default SEC1 IV mode; WOLFSSL_ECIES_STATIC_GCM_NONCE opts into the fixed-nonce GCM path so the GCM KAT/round-trip and cryptocb tests run.",
"configure": ["--enable-eccencrypt", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "ecies-geniv-gcm-static-nonce", "minutes": 2.0,
"comment": "Same ECIES-GCM coverage in the WOLFSSL_ECIES_GEN_IV mode (random embedded nonce).",
"configure": ["--enable-eccencrypt=geniv", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "ecies-old-gcm-static-nonce", "minutes": 2.0,
"comment": "Same ECIES-GCM coverage in the legacy WOLFSSL_ECIES_OLD mode (KDF-derived nonce, no ephemeral pubkey prepended).",
"configure": ["--enable-eccencrypt=old", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "opensslextra-x509small", "minutes": 2.0,
"configure": ["--enable-opensslextra=x509small"]},
{"name": "cryptocb-keygen-find", "minutes": 2.0,
+26
View File
@@ -2025,6 +2025,11 @@ int wc_ecc_ctx_set_info(ecEncCtx* ctx, const byte* info, int sz);
\param ctx Optional: pointer to an ecEncCtx object specifying different
encryption algorithms to use
\note Selecting an AES-GCM DEM algorithm (ecAES_128_GCM, ecAES_256_GCM) in
the default IV mode requires the WOLFSSL_ECIES_STATIC_GCM_NONCE build macro;
otherwise this function returns NOT_COMPILED_IN. See wc_ecc_encrypt_ex for
the full rationale.
_Example_
\code
byte msg[] = { initialize with msg to encrypt. Ensure padded to block size };
@@ -2072,6 +2077,9 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
small to store the encrypted ciphertext
\return MEMORY_E Returned if there is an error allocating memory
for the shared secret key
\return NOT_COMPILED_IN Returned if an AES-GCM DEM algorithm
(ecAES_128_GCM or ecAES_256_GCM) is requested in the default IV mode
without the WOLFSSL_ECIES_STATIC_GCM_NONCE build macro defined
\param privKey pointer to the ecc_key object containing the
private key to use for encryption
@@ -2088,6 +2096,16 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
encryption algorithms to use
\param compressed Public key field is to be output in compressed format.
\note The AES-GCM DEM algorithms (ecAES_128_GCM, ecAES_256_GCM) in the
default IV mode use a fixed all-zero GCM nonce. That is safe only because
ECIES derives a fresh symmetric key from a fresh ephemeral key on every
encryption, so the (key, nonce) pair never repeats; reusing the ephemeral
key is catastrophic for AES-GCM. For that reason the fixed-nonce GCM DEM is
off by default and must be enabled with the WOLFSSL_ECIES_STATIC_GCM_NONCE
build macro, otherwise this function returns NOT_COMPILED_IN for a GCM
algorithm. The macro is not needed with WOLFSSL_ECIES_GEN_IV (random
per-message nonce) or WOLFSSL_ECIES_OLD (nonce derived from the KDF output).
_Example_
\code
byte msg[] = { initialize with msg to encrypt. Ensure padded to block size };
@@ -2136,6 +2154,9 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
small to store the decrypted plaintext
\return MEMORY_E Returned if there is an error allocating memory
for the shared secret key
\return NOT_COMPILED_IN Returned if an AES-GCM DEM algorithm
(ecAES_128_GCM or ecAES_256_GCM) is requested in the default IV mode
without the WOLFSSL_ECIES_STATIC_GCM_NONCE build macro defined
\param privKey pointer to the ecc_key object containing the private
key to use for decryption
@@ -2150,6 +2171,11 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
\param ctx Optional: pointer to an ecEncCtx object specifying
different decryption algorithms to use
\note Selecting an AES-GCM DEM algorithm (ecAES_128_GCM, ecAES_256_GCM) in
the default IV mode requires the WOLFSSL_ECIES_STATIC_GCM_NONCE build macro;
otherwise this function returns NOT_COMPILED_IN. See wc_ecc_encrypt_ex for
the full rationale.
_Example_
\code
byte cipher[] = { initialize with
+384 -1
View File
@@ -1402,14 +1402,97 @@ int test_wc_ecc_ctx_set_info(void)
return EXPECT_RESULT();
} /* END test_wc_ecc_ctx_set_info */
/*
* Testing the crypto-callback context accessors wc_ecc_ctx_get_algo,
* wc_ecc_ctx_get_kdf_salt and wc_ecc_ctx_get_info (built only when
* WOLF_CRYPTO_CB is enabled).
*/
int test_wc_ecc_ctx_getters(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC)
ecEncCtx* ctx = NULL;
WC_RNG rng;
byte encAlgo = 0, kdfAlgo = 0, macAlgo = 0;
const byte* got = NULL;
word32 gotSz = 0;
WOLFSSL_SMALL_STACK_STATIC const byte salt[EXCHANGE_SALT_SZ] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
};
const char* info = "ctx getter info";
word32 infoSz = (word32)XSTRLEN(info);
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectNotNull(ctx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng));
/* get_algo: set then read back */
ExpectIntEQ(wc_ecc_ctx_set_algo(ctx, ecAES_256_GCM, ecHKDF_SHA256,
ecHMAC_SHA256), 0);
ExpectIntEQ(wc_ecc_ctx_get_algo(ctx, &encAlgo, &kdfAlgo, &macAlgo), 0);
ExpectIntEQ(encAlgo, ecAES_256_GCM);
ExpectIntEQ(kdfAlgo, ecHKDF_SHA256);
ExpectIntEQ(macAlgo, ecHMAC_SHA256);
/* individual NULL out-params are allowed (skipped) */
encAlgo = 0;
ExpectIntEQ(wc_ecc_ctx_get_algo(ctx, &encAlgo, NULL, NULL), 0);
ExpectIntEQ(encAlgo, ecAES_256_GCM);
/* bad arg: NULL ctx */
ExpectIntEQ(wc_ecc_ctx_get_algo(NULL, &encAlgo, &kdfAlgo, &macAlgo),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* get_kdf_salt: set then read back */
ExpectIntEQ(wc_ecc_ctx_set_kdf_salt(ctx, salt, (word32)sizeof(salt)), 0);
ExpectIntEQ(wc_ecc_ctx_get_kdf_salt(ctx, &got, &gotSz), 0);
ExpectIntEQ(gotSz, (word32)sizeof(salt));
ExpectNotNull(got);
ExpectIntEQ(XMEMCMP(got, salt, sizeof(salt)), 0);
/* bad args */
ExpectIntEQ(wc_ecc_ctx_get_kdf_salt(NULL, &got, &gotSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_kdf_salt(ctx, NULL, &gotSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_kdf_salt(ctx, &got, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* get_info: set then read back */
got = NULL; gotSz = 0;
ExpectIntEQ(wc_ecc_ctx_set_info(ctx, (const byte*)info, (int)infoSz), 0);
ExpectIntEQ(wc_ecc_ctx_get_info(ctx, &got, &gotSz), 0);
ExpectIntEQ(gotSz, infoSz);
ExpectNotNull(got);
ExpectIntEQ(XMEMCMP(got, info, infoSz), 0);
/* bad args */
ExpectIntEQ(wc_ecc_ctx_get_info(NULL, &got, &gotSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_info(ctx, NULL, &gotSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_info(ctx, &got, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
wc_ecc_ctx_free(ctx);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ctx_getters */
/*
* Testing wc_ecc_encrypt() and wc_ecc_decrypt()
*/
int test_wc_ecc_encryptDecrypt(void)
{
EXPECT_DECLS;
/* The test drives the default DEM (NULL ctx). That is AES-CBC when available;
* otherwise ecc_ctx_init falls back to AES-GCM, which in the default IV mode
* needs an opt-in (GEN_IV, OLD, or STATIC_GCM_NONCE) or wc_ecc_encrypt returns
* NOT_COMPILED_IN. Only build the test when the default DEM actually works. */
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128)
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
ecc_key srvKey;
ecc_key cliKey;
ecc_key tmpKey;
@@ -1510,6 +1593,306 @@ int test_wc_ecc_encryptDecrypt(void)
return EXPECT_RESULT();
} /* END test_wc_ecc_encryptDecrypt */
/*
* Testing ECIES with the AES-256-GCM DEM. Exercises, each with its own
* single-use client/server ctx pair:
* tc 0: round-trip succeeds and matches
* tc 1: tag corruption -> decrypt rejected (GCM authentication)
* tc 2: encrypt into too-small output buffer -> BUFFER_E
* tc 3: decrypt truncated input -> BAD_FUNC_ARG
* tc 4: decrypt into too-small plaintext buffer -> BUFFER_E
*/
int test_wc_ecc_ecies_gcm(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
!defined(NO_AES) && defined(HAVE_AESGCM) && defined(WOLFSSL_AES_256) && \
defined(HAVE_HKDF) && defined(WOLFSSL_ECIES_STATIC_GCM_NONCE) && \
!defined(WOLFSSL_NO_MALLOC)
WC_RNG rng;
int tc;
XMEMSET(&rng, 0, sizeof(rng));
ExpectIntEQ(wc_InitRng(&rng), 0);
for (tc = 0; tc <= 4 && EXPECT_SUCCESS(); tc++) {
ecc_key cliKey;
ecc_key srvKey;
ecEncCtx* cliCtx = NULL;
ecEncCtx* srvCtx = NULL;
byte msg[32];
byte out[256];
byte plain[64];
word32 outSz = (word32)sizeof(out);
word32 plainSz = (word32)sizeof(plain);
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt = NULL;
/* OLD format has no embedded ephemeral key, so decrypt needs the
* sender's public key; newer formats read it from the message. */
#ifdef WOLFSSL_ECIES_OLD
ecc_key* decPub;
#else
ecc_key* decPub = NULL;
#endif
int i;
XMEMSET(&cliKey, 0, sizeof(cliKey));
XMEMSET(&srvKey, 0, sizeof(srvKey));
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
ExpectIntEQ(wc_ecc_init(&cliKey), 0);
ExpectIntEQ(wc_ecc_init(&srvKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &cliKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &srvKey), 0);
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0);
ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0);
#endif
#ifdef WOLFSSL_ECIES_OLD
decPub = &cliKey;
#endif
ExpectNotNull(cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng));
ExpectNotNull(srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng));
ExpectIntEQ(wc_ecc_ctx_set_algo(cliCtx, ecAES_256_GCM, ecHKDF_SHA256,
ecHMAC_SHA256), 0);
ExpectIntEQ(wc_ecc_ctx_set_algo(srvCtx, ecAES_256_GCM, ecHKDF_SHA256,
ecHMAC_SHA256), 0);
/* exchange salts */
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx));
if (tmpSalt != NULL)
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx));
if (tmpSalt != NULL)
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt), 0);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt), 0);
if (tc == 2) {
/* encrypt into a buffer too small for pubKey+nonce+ct+tag */
word32 smallSz = 8;
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out,
&smallSz, cliCtx), WC_NO_ERR_TRACE(BUFFER_E));
}
else {
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out,
&outSz, cliCtx), 0);
if (tc == 0) {
ExpectIntEQ(wc_ecc_decrypt(&srvKey, decPub, out, outSz, plain,
&plainSz, srvCtx), 0);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
}
else if (tc == 1) {
/* flip a bit in the trailing GCM tag -> auth must reject with
* the specific GCM authentication error, proving the tag check
* (not an earlier size check) rejected it. */
if (EXPECT_SUCCESS() && outSz > 0)
out[outSz - 1] ^= 0x01;
ExpectIntEQ(wc_ecc_decrypt(&srvKey, decPub, out, outSz, plain,
&plainSz, srvCtx), WC_NO_ERR_TRACE(AES_GCM_AUTH_E));
}
else if (tc == 3) {
/* truncated input: below the smallest valid size in any IV
* mode (OLD needs only the tag, so use < digestSz) */
ExpectIntEQ(wc_ecc_decrypt(&srvKey, decPub, out, 8, plain,
&plainSz, srvCtx), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
else { /* tc == 4: plaintext buffer too small */
plainSz = 4;
ExpectIntEQ(wc_ecc_decrypt(&srvKey, decPub, out, outSz, plain,
&plainSz, srvCtx), WC_NO_ERR_TRACE(BUFFER_E));
}
}
wc_ecc_ctx_free(cliCtx);
wc_ecc_ctx_free(srvCtx);
wc_ecc_free(&srvKey);
wc_ecc_free(&cliKey);
}
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_gcm */
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
/* CryptoCb that services ECIES by forwarding to software (proving the dispatch
* path is reached), and reports UNAVAILABLE for everything else. The registered
* ctx is an int* invocation flag, set per direction; passing it through ctx (not
* a shared global) keeps the test safe if run concurrently. */
static int myEciesApiCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
int* invoked = (int*)ctx;
if (info->algo_type == WC_ALGO_TYPE_PK) {
if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
if (invoked != NULL)
*invoked = 1;
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
info->pk.eciesencrypt.privKey->devId = devIdArg;
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
if (invoked != NULL)
*invoked = 1;
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
}
}
return ret;
}
#endif
/*
* Testing ECIES encrypt/decrypt dispatch through the CryptoCb framework.
*/
int test_wc_ecc_ecies_cryptocb(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
const int cbDevId = 0x45434230; /* 'ECB0' */
ecc_key cliKey;
ecc_key srvKey;
WC_RNG rng;
byte msg[32];
byte out[256];
byte plain[64];
word32 outSz = (word32)sizeof(out);
word32 plainSz = (word32)sizeof(plain);
int i;
int registered = 0;
int cbInvoked = 0;
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&cliKey, 0, sizeof(cliKey));
XMEMSET(&srvKey, 0, sizeof(srvKey));
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(cbDevId, myEciesApiCryptoCb,
&cbInvoked), 0);
if (EXPECT_SUCCESS())
registered = 1;
ExpectIntEQ(wc_InitRng(&rng), 0);
/* build keys with software, then route ECIES through the callback */
ExpectIntEQ(wc_ecc_init(&cliKey), 0);
ExpectIntEQ(wc_ecc_init(&srvKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &cliKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &srvKey), 0);
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0);
ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0);
#endif
cliKey.devId = cbDevId;
srvKey.devId = cbDevId;
cbInvoked = 0;
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
NULL), 0);
/* callback must have serviced the encrypt */
ExpectIntEQ(cbInvoked, 1);
cbInvoked = 0;
/* OLD format needs the sender's public key supplied; newer formats take
* NULL and read the ephemeral key from the message. */
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain, &plainSz,
NULL), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz,
NULL), 0);
#endif
ExpectIntEQ(cbInvoked, 1);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
cliKey.devId = INVALID_DEVID;
srvKey.devId = INVALID_DEVID;
wc_ecc_free(&srvKey);
wc_ecc_free(&cliKey);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
if (registered)
wc_CryptoCb_UnRegisterDevice(cbDevId);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_cryptocb */
/*
* The ECIES AES-GCM DEM needs an RNG only in GEN_IV mode, where it generates a
* random per-message nonce (default mode uses a fixed nonce and OLD derives it
* from the KDF - neither needs an RNG). MISSING_RNG_E is therefore observable
* only when GCM is the *default* DEM (no AES-CBC/CTR in the build) AND
* WOLFSSL_ECIES_GEN_IV is set, so that encrypting with a NULL context (no RNG)
* and a key with no RNG hits the guard. Otherwise the test compiles out.
*/
int test_wc_ecc_ecies_gcm_no_rng(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
!defined(NO_AES) && defined(HAVE_AESGCM) && !defined(HAVE_AES_CBC) && \
!defined(WOLFSSL_AES_COUNTER) && defined(WOLFSSL_ECIES_GEN_IV) && \
!defined(WOLFSSL_NO_MALLOC) && \
(defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_256))
WC_RNG rng;
ecc_key cliKey;
ecc_key srvKey;
byte msg[32];
byte out[256];
word32 outSz = (word32)sizeof(out);
int i;
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&cliKey, 0, sizeof(cliKey));
XMEMSET(&srvKey, 0, sizeof(srvKey));
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ecc_init(&cliKey), 0);
ExpectIntEQ(wc_ecc_init(&srvKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &cliKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, 32, &srvKey), 0);
/* Deliberately do NOT call wc_ecc_set_rng() on cliKey, and pass a NULL
* context so no RNG is available for the GCM nonce. */
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
NULL), WC_NO_ERR_TRACE(MISSING_RNG_E));
wc_ecc_free(&srvKey);
wc_ecc_free(&cliKey);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_gcm_no_rng */
/*
* Testing wc_ecc_del_point() and wc_ecc_new_point()
*/
+8
View File
@@ -51,7 +51,11 @@ int test_wc_ecc_ctx_new(void);
int test_wc_ecc_ctx_reset(void);
int test_wc_ecc_ctx_set_peer_salt(void);
int test_wc_ecc_ctx_set_info(void);
int test_wc_ecc_ctx_getters(void);
int test_wc_ecc_encryptDecrypt(void);
int test_wc_ecc_ecies_gcm(void);
int test_wc_ecc_ecies_gcm_no_rng(void);
int test_wc_ecc_ecies_cryptocb(void);
int test_wc_ecc_del_point(void);
int test_wc_ecc_pointFns(void);
int test_wc_ecc_shared_secret_ssh(void);
@@ -94,7 +98,11 @@ int test_wc_EccDecisionCoverage4(void);
TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_reset), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_set_peer_salt), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_set_info), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ctx_getters), \
TEST_DECL_GROUP("ecc", test_wc_ecc_encryptDecrypt), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm_no_rng), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_cryptocb), \
TEST_DECL_GROUP("ecc", test_wc_ecc_del_point), \
TEST_DECL_GROUP("ecc", test_wc_ecc_pointFns), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_ssh), \
+160 -53
View File
@@ -13914,6 +13914,32 @@ exit:
#ifdef HAVE_ECC_ENCRYPT
/* Drive an ECIES exchange context to the SALT_SET state with fixed salts and a
* chosen DEM cipher. The ECIES contexts are single-use per message, so the
* per-cipher benchmark loops reset and re-prime the context before each op.
* Fixed salts let the encrypt/decrypt directions agree (required for GCM's
* authentication tag to verify). */
static int bench_ecies_prep(ecEncCtx* ctx, byte encAlgo, const byte* ownSalt,
const byte* peerSalt)
{
int ret;
byte* own;
ret = wc_ecc_ctx_reset(ctx, &gRng);
if (ret == 0)
ret = wc_ecc_ctx_set_algo(ctx, encAlgo, ecHKDF_SHA256, ecHMAC_SHA256);
if (ret == 0) {
own = (byte*)wc_ecc_ctx_get_own_salt(ctx);
if (own == NULL)
ret = BAD_FUNC_ARG;
else {
XMEMCPY(own, ownSalt, EXCHANGE_SALT_SZ);
ret = wc_ecc_ctx_set_peer_salt(ctx, peerSalt);
}
}
return ret;
}
void bench_eccEncrypt(int curveId)
{
#define BENCH_ECCENCRYPT_MSG_SIZE 48
@@ -13998,62 +14024,143 @@ void bench_eccEncrypt(int curveId)
msg[i] = (byte)i;
}
bench_stats_start(&count, &start);
do {
for (i = 0; i < ntimes; i++) {
/* One enc/dec benchmark pair per DEM cipher available in this build so the
* AES-CBC/CTR/GCM variants can be compared side by side. A trailing {0,NULL}
* sentinel keeps the table non-empty when only one cipher is enabled. */
{
WOLFSSL_SMALL_STACK_STATIC const byte fixedCliSalt[EXCHANGE_SALT_SZ] = {
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
};
WOLFSSL_SMALL_STACK_STATIC const byte fixedSrvSalt[EXCHANGE_SALT_SZ] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
};
static const struct { byte algo; const char* label; } eciesCiphers[] = {
#if !defined(NO_AES) && defined(HAVE_AES_CBC)
#ifdef WOLFSSL_AES_128
{ ecAES_128_CBC, "AES128CBC" },
#endif
#ifdef WOLFSSL_AES_256
{ ecAES_256_CBC, "AES256CBC" },
#endif
#endif
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
#ifdef WOLFSSL_AES_128
{ ecAES_128_CTR, "AES128CTR" },
#endif
#ifdef WOLFSSL_AES_256
{ ecAES_256_CTR, "AES256CTR" },
#endif
#endif
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)
#ifdef WOLFSSL_AES_128
{ ecAES_128_GCM, "AES128GCM" },
#endif
#ifdef WOLFSSL_AES_256
{ ecAES_256_GCM, "AES256GCM" },
#endif
#endif
{ 0, NULL } /* sentinel */
};
ecEncCtx* cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &gRng);
ecEncCtx* srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &gRng);
char encDesc[32];
char decDesc[32];
size_t c;
#ifdef WOLFSSL_ECIES_OLD
/* OLD format carries no ephemeral point, so decrypt needs the sender's
* public key. */
ecc_key* decPubKey = userA;
#else
/* SEC1 decrypt imports the ephemeral point into its pubKey argument, so
* pass NULL to avoid clobbering userA between cipher iterations. */
ecc_key* decPubKey = NULL;
#endif
(void)XSNPRINTF(name, BENCH_ECC_NAME_SZ, "ECC [%15s]",
wc_ecc_get_name(curveId));
if (cliCtx == NULL || srvCtx == NULL) {
printf("bench_eccEncrypt ctx alloc failed\n");
wc_ecc_ctx_free(cliCtx);
wc_ecc_ctx_free(srvCtx);
goto exit;
}
for (c = 0; eciesCiphers[c].label != NULL; c++) {
byte algo = eciesCiphers[c].algo;
(void)XSNPRINTF(encDesc, sizeof(encDesc), "%s-%s", desc[6],
eciesCiphers[c].label);
(void)XSNPRINTF(decDesc, sizeof(decDesc), "%s-%s", desc[7],
eciesCiphers[c].label);
/* encrypt msg to B */
ret = wc_ecc_encrypt(userA, userB, msg, BENCH_ECCENCRYPT_MSG_SIZE,
out, &outSz, NULL);
if (ret != 0) {
printf("wc_ecc_encrypt failed! %d\n", ret);
goto exit_enc;
}
RECORD_MULTI_VALUE_STATS();
bench_stats_start(&count, &start);
do {
for (i = 0; i < ntimes; i++) {
outSz = BENCH_ECCENCRYPT_OUT_SIZE;
ret = bench_ecies_prep(cliCtx, algo, fixedCliSalt,
fixedSrvSalt);
if (ret == 0)
ret = wc_ecc_encrypt(userA, userB, msg,
BENCH_ECCENCRYPT_MSG_SIZE, out, &outSz, cliCtx);
if (ret != 0) {
printf("wc_ecc_encrypt failed! %d\n", ret);
goto exit_ecies;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
bench_stats_asym_finish(name, keySize * 8, encDesc, 0, count, start,
ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
RESET_MULTI_VALUE_STATS_VARS();
/* decrypt the last ciphertext produced above (fixed salts make the
* server's derived keys match the client's, so GCM auth passes) */
bench_stats_start(&count, &start);
do {
for (i = 0; i < ntimes; i++) {
bench_plainSz = bench_size;
ret = bench_ecies_prep(srvCtx, algo, fixedSrvSalt,
fixedCliSalt);
if (ret == 0)
ret = wc_ecc_decrypt(userB, decPubKey, out, outSz,
bench_plain, &bench_plainSz, srvCtx);
if (ret != 0) {
printf("wc_ecc_decrypt failed! %d\n", ret);
goto exit_ecies;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
bench_stats_asym_finish(name, keySize * 8, decDesc, 0, count, start,
ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
RESET_MULTI_VALUE_STATS_VARS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
exit_enc:
(void)XSNPRINTF(name, BENCH_ECC_NAME_SZ, "ECC [%15s]",
wc_ecc_get_name(curveId));
bench_stats_asym_finish(name, keySize * 8, desc[6], 0, count, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
RESET_MULTI_VALUE_STATS_VARS();
if (ret != 0)
goto exit;
bench_stats_start(&count, &start);
do {
for (i = 0; i < ntimes; i++) {
/* decrypt msg from A */
ret = wc_ecc_decrypt(userB, userA, out, outSz, bench_plain,
&bench_plainSz, NULL);
if (ret != 0) {
printf("wc_ecc_decrypt failed! %d\n", ret);
goto exit_dec;
}
RECORD_MULTI_VALUE_STATS();
}
count += i;
} while (bench_stats_check(start)
#ifdef MULTI_VALUE_STATISTICS
|| runs < minimum_runs
#endif
);
exit_dec:
bench_stats_asym_finish(name, keySize * 8, desc[7], 0, count, start, ret);
#ifdef MULTI_VALUE_STATISTICS
bench_multi_value_stats(max, min, sum, squareSum, runs);
#endif
exit_ecies:
wc_ecc_ctx_free(cliCtx);
wc_ecc_ctx_free(srvCtx);
}
exit:
+64
View File
@@ -1022,6 +1022,70 @@ int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder, int checkPriv)
return wc_CryptoCb_TranslateErrorCode(ret);
}
#endif /* HAVE_ECC_CHECK_KEY */
#ifdef HAVE_ECC_ENCRYPT
int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx,
int compressed)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
CryptoCb* dev;
if (privKey == NULL)
return ret;
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(privKey->devId, WC_ALGO_TYPE_PK);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
cryptoInfo.algo_type = WC_ALGO_TYPE_PK;
cryptoInfo.pk.type = WC_PK_TYPE_ECIES_ENCRYPT;
cryptoInfo.pk.eciesencrypt.privKey = privKey;
cryptoInfo.pk.eciesencrypt.pubKey = pubKey;
cryptoInfo.pk.eciesencrypt.msg = msg;
cryptoInfo.pk.eciesencrypt.msgSz = msgSz;
cryptoInfo.pk.eciesencrypt.out = out;
cryptoInfo.pk.eciesencrypt.outSz = outSz;
cryptoInfo.pk.eciesencrypt.ctx = ctx;
cryptoInfo.pk.eciesencrypt.compressed = compressed;
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
}
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_EciesDecrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
CryptoCb* dev;
if (privKey == NULL)
return ret;
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(privKey->devId, WC_ALGO_TYPE_PK);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
cryptoInfo.algo_type = WC_ALGO_TYPE_PK;
cryptoInfo.pk.type = WC_PK_TYPE_ECIES_DECRYPT;
cryptoInfo.pk.eciesdecrypt.privKey = privKey;
cryptoInfo.pk.eciesdecrypt.pubKey = pubKey;
cryptoInfo.pk.eciesdecrypt.msg = msg;
cryptoInfo.pk.eciesdecrypt.msgSz = msgSz;
cryptoInfo.pk.eciesdecrypt.out = out;
cryptoInfo.pk.eciesdecrypt.outSz = outSz;
cryptoInfo.pk.eciesdecrypt.ctx = ctx;
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
}
return wc_CryptoCb_TranslateErrorCode(ret);
}
#endif /* HAVE_ECC_ENCRYPT */
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
+350 -37
View File
@@ -133,6 +133,18 @@ Possible ECC enable options:
* (includes public key in shared secret).
* WOLFSSL_ECIES_GEN_IV: Generates random IV for ECIES default: off
* encryption instead of deriving from KDF.
* WOLFSSL_ECIES_STATIC_GCM_NONCE: default: off
* Allows the AES-GCM DEM in the default IV mode, where the
* GCM nonce is a fixed all-zero value that is not sent.
* This is ONLY safe because ECIES derives a fresh key from
* a fresh ephemeral key each message, so the (key, nonce)
* pair never repeats. Reusing the ephemeral key would
* reuse both the key and the nonce - catastrophic for GCM.
* Off by default: without this define, the GCM DEM returns
* NOT_COMPILED_IN in the default IV mode so the fixed nonce
* cannot be selected by accident. Not needed with
* WOLFSSL_ECIES_GEN_IV (random nonce) or WOLFSSL_ECIES_OLD
* (KDF-derived nonce).
*
* Fixed Point Cache options (requires FP_ECC):
* FP_ENTRIES: Number of FP cache entries default: 15
@@ -14837,6 +14849,50 @@ int wc_ecc_ctx_set_algo(ecEncCtx* ctx, byte encAlgo, byte kdfAlgo, byte macAlgo)
return 0;
}
#ifdef WOLF_CRYPTO_CB
/* Read back the parameters a caller configured on the context. Intended for
* crypto-callback backends (e.g. a hardware ECIES engine) that must reproduce
* the algorithm, KDF salt and KDF info to run the operation off-device. Only
* built when crypto callbacks are enabled, so default builds are unaffected. */
int wc_ecc_ctx_get_algo(ecEncCtx* ctx, byte* encAlgo, byte* kdfAlgo,
byte* macAlgo)
{
if (ctx == NULL)
return BAD_FUNC_ARG;
if (encAlgo != NULL)
*encAlgo = ctx->encAlgo;
if (kdfAlgo != NULL)
*kdfAlgo = ctx->kdfAlgo;
if (macAlgo != NULL)
*macAlgo = ctx->macAlgo;
return 0;
}
int wc_ecc_ctx_get_kdf_salt(ecEncCtx* ctx, const byte** salt, word32* sz)
{
if (ctx == NULL || salt == NULL || sz == NULL)
return BAD_FUNC_ARG;
*salt = ctx->kdfSalt;
*sz = ctx->kdfSaltSz;
return 0;
}
int wc_ecc_ctx_get_info(ecEncCtx* ctx, const byte** info, word32* sz)
{
if (ctx == NULL || info == NULL || sz == NULL)
return BAD_FUNC_ARG;
*info = ctx->kdfInfo;
*sz = ctx->kdfInfoSz;
return 0;
}
#endif /* WOLF_CRYPTO_CB */
const byte* wc_ecc_ctx_get_own_salt(ecEncCtx* ctx)
{
@@ -15024,6 +15080,12 @@ static void ecc_ctx_init(ecEncCtx* ctx, int flags, WC_RNG* rng)
#else
ctx->encAlgo = ecAES_128_CTR;
#endif
#elif !defined(NO_AES) && defined(HAVE_AESGCM)
#ifdef WOLFSSL_AES_128
ctx->encAlgo = ecAES_128_GCM;
#else
ctx->encAlgo = ecAES_256_GCM;
#endif
#else
#error "No valid encryption algorithm for ECIES configured."
#endif
@@ -15093,6 +15155,18 @@ void wc_ecc_ctx_free(ecEncCtx* ctx)
}
}
#if !defined(NO_AES) && defined(HAVE_AESGCM)
/* Is the ECIES encryption algorithm an AES-GCM (AEAD) mode? GCM replaces the
* AES + HMAC pair with a single authenticated-encryption pass. */
static WC_INLINE int ecc_is_gcm(byte encAlgo)
{
return (encAlgo == ecAES_128_GCM || encAlgo == ecAES_256_GCM);
}
#else
/* Compile GCM branches out entirely when AES-GCM isn't available. */
#define ecc_is_gcm(encAlgo) (0)
#endif
static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
int* keysLen, word32* digestSz, word32* blockSz)
{
@@ -15121,26 +15195,57 @@ static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
*ivSz = 12;
*blockSz = 1;
break;
#endif
#if !defined(NO_AES) && defined(HAVE_AESGCM)
case ecAES_128_GCM:
*encKeySz = KEY_SIZE_128;
*ivSz = AES_GCM_NONCE_SZ;
*blockSz = 1;
break;
case ecAES_256_GCM:
*encKeySz = KEY_SIZE_256;
*ivSz = AES_GCM_NONCE_SZ;
*blockSz = 1;
break;
#endif
default:
return BAD_FUNC_ARG;
}
switch (ctx->macAlgo) {
case ecHMAC_SHA256:
*digestSz = WC_SHA256_DIGEST_SIZE;
break;
default:
return BAD_FUNC_ARG;
if (ecc_is_gcm(ctx->encAlgo)) {
/* GCM is AEAD: the 16-byte tag replaces the HMAC digest, and no
* separate MAC algorithm/key is used. */
*digestSz = AES_GCM_TAG_SZ;
}
else {
switch (ctx->macAlgo) {
case ecHMAC_SHA256:
*digestSz = WC_SHA256_DIGEST_SIZE;
break;
default:
return BAD_FUNC_ARG;
}
}
} else
return BAD_FUNC_ARG;
if (ecc_is_gcm(ctx->encAlgo)) {
/* No MAC key. The nonce follows the ECIES IV build mode, matching the
* CBC/CTR DEMs: derived from the KDF (OLD), a fresh random value
* (GEN_IV), or a fixed zero (default). */
#ifdef WOLFSSL_ECIES_OLD
*keysLen = *encKeySz + *ivSz + (int)*digestSz;
*keysLen = *encKeySz + *ivSz; /* nonce is part of the KDF output */
#else
*keysLen = *encKeySz + (int)*digestSz;
*keysLen = *encKeySz;
#endif
}
else {
#ifdef WOLFSSL_ECIES_OLD
*keysLen = *encKeySz + *ivSz + (int)*digestSz;
#else
*keysLen = *encKeySz + (int)*digestSz;
#endif
}
return 0;
}
@@ -15192,6 +15297,19 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
outSz == NULL)
return BAD_FUNC_ARG;
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (privKey->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_EciesEncrypt(privKey, pubKey, msg, msgSz, out, outSz,
ctx, compressed);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
ret = 0; /* fall-through to software */
}
#endif
if (ctx == NULL) { /* use defaults */
ecc_ctx_init(&localCtx, 0, NULL);
ctx = &localCtx;
@@ -15202,6 +15320,15 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if (ret != 0)
return ret;
#if !defined(WOLFSSL_ECIES_OLD) && !defined(WOLFSSL_ECIES_GEN_IV) && \
!defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)
/* Default IV mode gives the GCM DEM a fixed (zero) nonce, which is only safe
* with a fresh ephemeral key per message. Require explicit opt-in so it is
* never selected by accident; see WOLFSSL_ECIES_STATIC_GCM_NONCE. */
if (ecc_is_gcm(ctx->encAlgo))
return NOT_COMPILED_IN;
#endif
#ifndef WOLFSSL_ECIES_OLD
if (!compressed) {
pubKeySz = 1 + (word32)wc_ecc_size(privKey) * 2;
@@ -15235,16 +15362,32 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if ((msgSz % blockSz) != 0)
return BAD_PADDING_E;
if (ecc_is_gcm(ctx->encAlgo)) {
/* Nonce is embedded in the output only in GEN_IV mode; OLD derives it
* from the KDF and default uses a fixed nonce (neither is sent). */
#ifdef WOLFSSL_ECIES_OLD
if (*outSz < (msgSz + digestSz))
return BUFFER_E;
if (*outSz < (msgSz + digestSz))
return BUFFER_E;
#elif defined(WOLFSSL_ECIES_GEN_IV)
if (*outSz < (pubKeySz + ivSz + msgSz + digestSz))
return BUFFER_E;
if (*outSz < (pubKeySz + (word32)ivSz + msgSz + digestSz))
return BUFFER_E;
#else
if (*outSz < (pubKeySz + msgSz + digestSz))
return BUFFER_E;
if (*outSz < (pubKeySz + msgSz + digestSz))
return BUFFER_E;
#endif
}
else {
#ifdef WOLFSSL_ECIES_OLD
if (*outSz < (msgSz + digestSz))
return BUFFER_E;
#elif defined(WOLFSSL_ECIES_GEN_IV)
if (*outSz < (pubKeySz + ivSz + msgSz + digestSz))
return BUFFER_E;
#else
if (*outSz < (pubKeySz + msgSz + digestSz))
return BUFFER_E;
#endif
}
#ifdef ECC_TIMING_RESISTANT
if (ctx->rng != NULL && privKey->rng == NULL)
@@ -15342,22 +15485,47 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
}
if (ret == 0) {
if (ecc_is_gcm(ctx->encAlgo)) {
/* GCM nonce follows the ECIES IV build mode, matching CBC/CTR:
* OLD -> from the KDF output; GEN_IV -> fresh random, embedded;
* default -> fixed zero. No MAC key. */
encKey = keys + offset;
macKey = NULL;
#ifdef WOLFSSL_ECIES_OLD
encIv = encKey + encKeySz;
#elif defined(WOLFSSL_ECIES_GEN_IV)
{
WC_RNG* rng = (privKey->rng != NULL) ? privKey->rng : ctx->rng;
encIv = out;
out += ivSz;
if (rng == NULL)
ret = MISSING_RNG_E;
else
ret = wc_RNG_GenerateBlock(rng, encIv, (word32)ivSz);
}
#else
XMEMSET(iv, 0, (size_t)ivSz);
encIv = iv;
#endif
}
else {
#ifdef WOLFSSL_ECIES_OLD
encKey = keys + offset;
encIv = encKey + encKeySz;
macKey = encKey + encKeySz + ivSz;
encKey = keys + offset;
encIv = encKey + encKeySz;
macKey = encKey + encKeySz + ivSz;
#elif defined(WOLFSSL_ECIES_GEN_IV)
encKey = keys + offset;
encIv = out;
out += ivSz;
macKey = encKey + encKeySz;
ret = wc_RNG_GenerateBlock(privKey->rng, encIv, ivSz);
encKey = keys + offset;
encIv = out;
out += ivSz;
macKey = encKey + encKeySz;
ret = wc_RNG_GenerateBlock(privKey->rng, encIv, ivSz);
#else
XMEMSET(iv, 0, (size_t)ivSz);
encKey = keys + offset;
encIv = iv;
macKey = encKey + encKeySz;
XMEMSET(iv, 0, (size_t)ivSz);
encKey = keys + offset;
encIv = iv;
macKey = encKey + encKeySz;
#endif
}
}
if (ret == 0) {
@@ -15376,7 +15544,7 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#else
Aes aes[1];
#endif
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_AesSetKey(aes, encKey, (word32)encKeySz, encIv,
AES_ENCRYPTION);
@@ -15417,7 +15585,7 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
XMEMSET(ctr_iv + WOLFSSL_ECIES_GEN_IV_SIZE, 0,
WC_AES_BLOCK_SIZE - WOLFSSL_ECIES_GEN_IV_SIZE);
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_AesSetKey(aes, encKey, (word32)encKeySz, ctr_iv,
AES_ENCRYPTION);
@@ -15437,13 +15605,50 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#endif
break;
}
#if !defined(NO_AES) && defined(HAVE_AESGCM)
case ecAES_128_GCM:
case ecAES_256_GCM:
{
#ifdef WOLFSSL_SMALL_STACK
Aes *aes = (Aes *)XMALLOC(sizeof *aes, ctx->heap,
DYNAMIC_TYPE_AES);
if (aes == NULL) {
ret = MEMORY_E;
break;
}
#else
Aes aes[1];
#endif
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes, encKey, (word32)encKeySz);
if (ret == 0) {
/* tag is written directly after the ciphertext; the
* mac salt (if any) is bound in as AAD, mirroring the
* HMAC salt used by the CBC/CTR paths. */
ret = wc_AesGcmEncrypt(aes, out, msg, msgSz,
encIv, (word32)ivSz,
out + msgSz, digestSz,
ctx->macSalt, ctx->macSaltSz);
#if defined(WOLFSSL_ASYNC_CRYPT) && \
defined(WC_ASYNC_ENABLE_AES)
ret = wc_AsyncWait(ret, &aes->asyncDev,
WC_ASYNC_FLAG_NONE);
#endif
}
wc_AesFree(aes);
}
WC_FREE_VAR_EX(aes, ctx->heap, DYNAMIC_TYPE_AES);
break;
}
#endif
default:
ret = BAD_FUNC_ARG;
break;
}
}
if (ret == 0) {
if (ret == 0 && !ecc_is_gcm(ctx->encAlgo)) {
switch (ctx->macAlgo) {
case ecHMAC_SHA256:
{
@@ -15457,7 +15662,7 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#else
Hmac hmac[1];
#endif
ret = wc_HmacInit(hmac, NULL, INVALID_DEVID);
ret = wc_HmacInit(hmac, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_HmacSetKey(hmac, WC_SHA256, macKey,
WC_SHA256_DIGEST_SIZE);
@@ -15486,13 +15691,25 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
}
if (ret == 0) {
if (ecc_is_gcm(ctx->encAlgo)) {
/* Nonce is only in the output in GEN_IV mode. */
#ifdef WOLFSSL_ECIES_OLD
*outSz = msgSz + digestSz;
*outSz = msgSz + digestSz;
#elif defined(WOLFSSL_ECIES_GEN_IV)
*outSz = pubKeySz + ivSz + msgSz + digestSz;
*outSz = pubKeySz + (word32)ivSz + msgSz + digestSz;
#else
*outSz = pubKeySz + msgSz + digestSz;
*outSz = pubKeySz + msgSz + digestSz;
#endif
}
else {
#ifdef WOLFSSL_ECIES_OLD
*outSz = msgSz + digestSz;
#elif defined(WOLFSSL_ECIES_GEN_IV)
*outSz = pubKeySz + ivSz + msgSz + digestSz;
#else
*outSz = pubKeySz + msgSz + digestSz;
#endif
}
}
ForceZero(sharedSecret, sharedSz);
@@ -15564,6 +15781,19 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
return BAD_FUNC_ARG;
#endif
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (privKey->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_EciesDecrypt(privKey, pubKey, msg, msgSz, out, outSz,
ctx);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
ret = 0; /* fall-through to software */
}
#endif
if (ctx == NULL) { /* use defaults */
ecc_ctx_init(&localCtx, 0, NULL);
ctx = &localCtx;
@@ -15574,6 +15804,15 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if (ret != 0)
return ret;
#if !defined(WOLFSSL_ECIES_OLD) && !defined(WOLFSSL_ECIES_GEN_IV) && \
!defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)
/* Default IV mode gives the GCM DEM a fixed (zero) nonce, which is only safe
* with a fresh ephemeral key per message. Require explicit opt-in so it is
* never selected by accident; see WOLFSSL_ECIES_STATIC_GCM_NONCE. */
if (ecc_is_gcm(ctx->encAlgo))
return NOT_COMPILED_IN;
#endif
#ifndef WOLFSSL_ECIES_OLD
ret = ecc_public_key_size(privKey, &pubKeySz);
if (ret != 0)
@@ -15604,6 +15843,27 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if (keysLen > ECC_BUFSIZE) /* keys size */
return BUFFER_E;
if (ecc_is_gcm(ctx->encAlgo)) {
/* GCM has a trailing tag (digestSz) and no block padding. The nonce is
* only present in the input in GEN_IV mode. */
#ifdef WOLFSSL_ECIES_OLD
if (msgSz < digestSz)
return BAD_FUNC_ARG;
if (*outSz < (msgSz - digestSz))
return BUFFER_E;
#elif defined(WOLFSSL_ECIES_GEN_IV)
if (msgSz < pubKeySz + (word32)ivSz + digestSz)
return BAD_FUNC_ARG;
if (*outSz < (msgSz - (word32)ivSz - digestSz - pubKeySz))
return BUFFER_E;
#else
if (msgSz < pubKeySz + digestSz)
return BAD_FUNC_ARG;
if (*outSz < (msgSz - digestSz - pubKeySz))
return BUFFER_E;
#endif
}
else {
#ifdef WOLFSSL_ECIES_OLD
if (((msgSz - digestSz) % blockSz) != 0)
return BAD_PADDING_E;
@@ -15627,6 +15887,7 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if (*outSz < (msgSz - digestSz - pubKeySz))
return BUFFER_E;
#endif
}
#ifdef ECC_TIMING_RESISTANT
if (ctx->rng != NULL && privKey->rng == NULL)
@@ -15741,7 +16002,23 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
}
}
if (ret == 0) {
if (ret == 0 && ecc_is_gcm(ctx->encAlgo)) {
/* GCM nonce follows the ECIES IV build mode (matching CBC/CTR); no MAC
* key and no separate HMAC verify (GCM authenticates on decrypt). */
encKey = keys + offset;
macKey = NULL;
#ifdef WOLFSSL_ECIES_OLD
encIv = encKey + encKeySz;
#elif defined(WOLFSSL_ECIES_GEN_IV)
encIv = msg;
msg += ivSz;
msgSz -= (word32)ivSz;
#else
XMEMSET(iv, 0, (size_t)ivSz);
encIv = iv;
#endif
}
else if (ret == 0) {
#ifdef WOLFSSL_ECIES_OLD
encKey = keys + offset;
encIv = encKey + encKeySz;
@@ -15773,7 +16050,7 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#else
Hmac hmac[1];
#endif
ret = wc_HmacInit(hmac, NULL, INVALID_DEVID);
ret = wc_HmacInit(hmac, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_HmacSetKey(hmac, WC_SHA256, macKey,
WC_SHA256_DIGEST_SIZE);
@@ -15823,7 +16100,7 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#else
Aes aes[1];
#endif
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_AesSetKey(aes, encKey, (word32)encKeySz, encIv,
AES_DECRYPTION);
@@ -15855,7 +16132,7 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
#else
Aes aes[1];
#endif
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
byte ctr_iv[WC_AES_BLOCK_SIZE];
/* Make a 16 byte IV from the bytes passed in. */
@@ -15877,6 +16154,42 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
WC_FREE_VAR_EX(aes, ctx->heap, DYNAMIC_TYPE_AES);
break;
}
#endif
#if !defined(NO_AES) && defined(HAVE_AESGCM)
case ecAES_128_GCM:
case ecAES_256_GCM:
{
#ifdef WOLFSSL_SMALL_STACK
Aes *aes = (Aes *)XMALLOC(sizeof *aes, ctx->heap,
DYNAMIC_TYPE_AES);
if (aes == NULL) {
ret = MEMORY_E;
break;
}
#else
Aes aes[1];
#endif
ret = wc_AesInit(aes, privKey->heap, privKey->devId);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes, encKey, (word32)encKeySz);
if (ret == 0) {
/* tag trails the ciphertext; mac salt (if any) is the
* AAD. A tag mismatch returns AES_GCM_AUTH_E. */
ret = wc_AesGcmDecrypt(aes, out, msg, msgSz - digestSz,
encIv, (word32)ivSz,
msg + msgSz - digestSz, digestSz,
ctx->macSalt, ctx->macSaltSz);
#if defined(WOLFSSL_ASYNC_CRYPT) && \
defined(WC_ASYNC_ENABLE_AES)
ret = wc_AsyncWait(ret, &aes->asyncDev,
WC_ASYNC_FLAG_NONE);
#endif
}
wc_AesFree(aes);
}
WC_FREE_VAR_EX(aes, ctx->heap, DYNAMIC_TYPE_AES);
break;
}
#endif
default:
ret = BAD_FUNC_ARG;
+539
View File
@@ -45019,6 +45019,36 @@ static wc_test_ret_t ecc_encrypt_combos_test(WC_RNG* rng, ecc_key* userA,
}
#endif
#endif /* !NO_AES && WOLFSSL_AES_COUNTER */
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE) && !defined(WOLFSSL_NO_MALLOC)
#ifdef WOLFSSL_AES_128
if (ret == 0) {
ret = ecc_encrypt_e2e_test(rng, userA, userB, ecAES_128_GCM,
ecHKDF_SHA256, ecHMAC_SHA256);
if (ret != 0) {
printf("ECIES: AES_128_GCM, HKDF_SHA256\n");
}
}
#ifdef HAVE_X963_KDF
if (ret == 0) {
ret = ecc_encrypt_e2e_test(rng, userA, userB, ecAES_128_GCM,
ecKDF_X963_SHA256, ecHMAC_SHA256);
if (ret != 0) {
printf("ECIES: AES_128_GCM, KDF_X963_SHA256\n");
}
}
#endif
#endif
#ifdef WOLFSSL_AES_256
if (ret == 0) {
ret = ecc_encrypt_e2e_test(rng, userA, userB, ecAES_256_GCM,
ecHKDF_SHA256, ecHMAC_SHA256);
if (ret != 0) {
printf("ECIES: AES_256_GCM, HKDF_SHA256\n");
}
}
#endif
#endif /* !NO_AES && HAVE_AESGCM */
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && !defined(WOLFSSL_NO_MALLOC)
if (ret == 0) {
ret = ecc_ctx_kdf_salt_test(rng, userA, userB);
@@ -45030,6 +45060,483 @@ static wc_test_ret_t ecc_encrypt_combos_test(WC_RNG* rng, ecc_key* userA,
(void)userB;
return ret;
}
/* Fixed-vector (decrypt-only) KAT + negative tests for ECIES with an AES-GCM
* DEM. ECIES is non-deterministic (random ephemeral key + random GCM nonce),
* so each ciphertext is captured once and decrypted here with a FIXED recipient
* private key and FIXED exchange salts. The salt mixing in
* wc_ecc_ctx_set_peer_salt() is symmetric, so decrypt reproduces the KDF/MAC
* salts from the blob alone. Only valid for the default SEC1 wire format.
*
* ecc_encrypt_gcm_kat_vec() is parameterized over (encAlgo, kdfAlgo, blob) so
* the same body validates every captured vector below. */
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
defined(HAVE_HKDF) && !defined(WOLFSSL_ECIES_OLD) && \
!defined(WOLFSSL_ECIES_ISO18033) && !defined(WOLFSSL_ECIES_GEN_IV) && \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE) && !defined(WOLFSSL_NO_MALLOC)
/* recipient private key (SECP256R1 raw scalar) - shared by every GCM vector.
* File-scope so all vectors share them; must be 'static' (internal linkage)
* because WOLFSSL_SMALL_STACK_STATIC expands to nothing in non-small-stack
* builds, which at file scope would create external globals. */
static const byte ecc_gcm_kat_privKey[] = {
0x04, 0x80, 0xef, 0x1d, 0xbe, 0x02, 0x0c, 0x20,
0x5b, 0xab, 0x80, 0x35, 0x5b, 0x2a, 0x0f, 0x6d,
0xd3, 0xb0, 0x7f, 0x7e, 0x7f, 0x86, 0x8a, 0x49,
0xee, 0xb4, 0xaa, 0x09, 0x2d, 0x1e, 0x1d, 0x02
};
/* fixed exchange salts (client's own, server's own) */
static const byte ecc_gcm_kat_cliSalt[EXCHANGE_SALT_SZ] = {
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
};
static const byte ecc_gcm_kat_srvSalt[EXCHANGE_SALT_SZ] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
};
/* the fixed 48-byte plaintext every vector encrypts */
static const byte ecc_gcm_kat_msg[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
};
/* Decrypt-side KAT for one captured vector, plus tamper passes:
* i==0 valid blob -> success + plaintext matches
* i==1 corrupt GCM tag -> auth failure
* i==2 corrupt ciphertext -> auth failure
* (Buffer-size and truncated-input error paths are covered by the API unit
* test test_wc_ecc_ecies_gcm().) A fresh server ctx is built each pass since
* the exchange ctx is single-use. */
static wc_test_ret_t ecc_encrypt_gcm_kat_vec(WC_RNG* rng, byte encAlgo,
byte kdfAlgo, const byte* enc_msg, word32 enc_msgSz)
{
wc_test_ret_t ret = 0;
ecc_key* userB = NULL;
byte* bad = NULL;
byte plain[sizeof(ecc_gcm_kat_msg)];
word32 plainSz;
int i;
int userBInit = 0;
userB = (ecc_key*)XMALLOC(sizeof(*userB), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
bad = (byte*)XMALLOC(enc_msgSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (userB == NULL || bad == NULL) {
ret = WC_TEST_RET_ENC_ERRNO;
goto vec_done;
}
for (i = 0; i <= 2 && ret == 0; i++) {
ecEncCtx* srvCtx = NULL;
const byte* in = enc_msg;
if (userBInit) {
wc_ecc_free(userB);
userBInit = 0;
}
ret = wc_ecc_init_ex(userB, HEAP_HINT, devId);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); break; }
userBInit = 1;
ret = wc_ecc_import_private_key_ex(ecc_gcm_kat_privKey,
(word32)sizeof(ecc_gcm_kat_privKey), NULL, 0, userB,
ECC_SECP256R1);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); break; }
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ret = wc_ecc_set_rng(userB, rng);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); break; }
#endif
srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, rng);
if (srvCtx == NULL) { ret = WC_TEST_RET_ENC_ERRNO; break; }
ret = wc_ecc_ctx_set_algo(srvCtx, encAlgo, kdfAlgo, ecHMAC_SHA256);
if (ret == 0) {
/* force our fixed own salt, then set the peer's fixed salt */
byte* ownSalt = (byte*)wc_ecc_ctx_get_own_salt(srvCtx);
if (ownSalt == NULL) {
ret = WC_TEST_RET_ENC_NC;
}
else {
XMEMCPY(ownSalt, ecc_gcm_kat_srvSalt, EXCHANGE_SALT_SZ);
ret = wc_ecc_ctx_set_peer_salt(srvCtx, ecc_gcm_kat_cliSalt);
}
}
if (ret != 0) {
wc_ecc_ctx_free(srvCtx);
ret = WC_TEST_RET_ENC_EC(ret);
break;
}
plainSz = sizeof(plain);
if (i == 1) { /* corrupt the trailing GCM tag */
XMEMCPY(bad, enc_msg, enc_msgSz);
bad[enc_msgSz - 1] ^= 0x01;
in = bad;
}
else if (i == 2) { /* corrupt a ciphertext byte */
XMEMCPY(bad, enc_msg, enc_msgSz);
bad[enc_msgSz - (word32)sizeof(ecc_gcm_kat_msg)] ^= 0x01;
in = bad;
}
ret = wc_ecc_decrypt(userB, NULL, in, enc_msgSz, plain, &plainSz,
srvCtx);
wc_ecc_ctx_free(srvCtx);
if (i == 0) {
/* valid blob must decrypt and match */
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); break; }
if (plainSz != sizeof(ecc_gcm_kat_msg) ||
XMEMCMP(plain, ecc_gcm_kat_msg,
sizeof(ecc_gcm_kat_msg)) != 0) {
ret = WC_TEST_RET_ENC_NC;
break;
}
}
else {
/* corrupted blob must be rejected by GCM authentication */
if (ret == 0) { ret = WC_TEST_RET_ENC_NC; break; }
ret = 0; /* expected failure -> continue */
}
}
vec_done:
if (userBInit)
wc_ecc_free(userB);
XFREE(userB, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(bad, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
/* Run every fixed GCM KAT vector available in this build. */
static wc_test_ret_t ecc_encrypt_gcm_kat(WC_RNG* rng)
{
wc_test_ret_t ret = 0;
#ifdef WOLFSSL_AES_256
/* AES-256-GCM, HKDF-SHA256, SEC1 default mode (fixed zero nonce, not sent):
* 0x04||point(65)||ciphertext(48)||tag(16). Generated with OpenSSL's
* (NIST SP 800-38D) AES-GCM so wolfSSL decrypting it validates the DEM. */
WOLFSSL_SMALL_STACK_STATIC const byte enc_msg_256_hkdf[] = {
0x04, 0x2a, 0x15, 0xd9, 0x15, 0xec, 0x17, 0xf0,
0xcb, 0xa0, 0x16, 0xcb, 0x87, 0x8b, 0xb5, 0x0a,
0x71, 0x88, 0xd9, 0x62, 0xdc, 0x66, 0x08, 0x03,
0x37, 0xbf, 0xff, 0x04, 0x9f, 0xae, 0x32, 0xa5,
0x1f, 0xa2, 0x30, 0xbc, 0x18, 0x01, 0x01, 0xc3,
0x87, 0x37, 0xd4, 0xd5, 0xbc, 0xa2, 0x72, 0xe7,
0x91, 0xc7, 0xeb, 0x3d, 0x52, 0x2e, 0xe1, 0x12,
0x07, 0x77, 0x56, 0x35, 0xed, 0x57, 0xf8, 0x9e,
0xae, 0xb4, 0xb8, 0x29, 0x89, 0xdf, 0x6f, 0xda,
0xbf, 0xdf, 0xd4, 0x08, 0x67, 0x9d, 0x76, 0x11,
0x55, 0x44, 0x86, 0x56, 0xc2, 0x62, 0x70, 0x1e,
0xd7, 0x30, 0xec, 0x61, 0x91, 0xb6, 0x22, 0x57,
0x41, 0x71, 0x6e, 0x5c, 0xbd, 0x91, 0x63, 0x14,
0x81, 0x12, 0x17, 0x98, 0x67, 0x8a, 0xfb, 0xa7,
0xba, 0x2f, 0x36, 0xd9, 0xba, 0xa8, 0xda, 0xda,
0xd9, 0x89, 0xbd, 0xf8, 0x21, 0x55, 0x43, 0x88,
0x19
};
if (ret == 0) {
ret = ecc_encrypt_gcm_kat_vec(rng, ecAES_256_GCM, ecHKDF_SHA256,
enc_msg_256_hkdf, (word32)sizeof(enc_msg_256_hkdf));
}
#endif /* WOLFSSL_AES_256 */
#ifdef WOLFSSL_AES_128
/* AES-128-GCM, HKDF-SHA256, SEC1 format */
WOLFSSL_SMALL_STACK_STATIC const byte enc_msg_128_hkdf[] = {
0x04,0x33,0xb1,0x00,0x18,0x4a,0x91,0x6e,
0x4d,0x4b,0xad,0x90,0xfb,0x25,0xaa,0xe7,
0x1b,0x82,0x38,0xda,0xab,0x85,0x51,0x91,
0xb8,0xd9,0xf8,0xa4,0x7b,0x7d,0xca,0x4d,
0x03,0xe4,0xe1,0x44,0xcf,0xf6,0x9e,0x70,
0x6f,0x23,0x2a,0xaf,0xcd,0x16,0xe4,0x02,
0x14,0x0c,0xf7,0x0b,0x1d,0x24,0x1a,0xf3,
0xc1,0xa8,0xe3,0x8e,0x96,0xa1,0x63,0xe0,
0x0d,0xa5,0xdd,0x32,0x27,0xdb,0x01,0x57,
0x59,0x65,0x2b,0xa8,0x32,0xdc,0x03,0x59,
0x5a,0xc7,0xb2,0xb7,0x1c,0xef,0x03,0xc5,
0x05,0x84,0x03,0x9d,0x6b,0x7c,0x59,0x65,
0xeb,0xa1,0x67,0xfb,0x94,0xd6,0x7d,0xa1,
0x22,0x58,0xf5,0x35,0x55,0xd7,0x5c,0x36,
0xb6,0x48,0x01,0x0a,0x8c,0x24,0xac,0x85,
0x20,0xab,0x13,0xac,0xe9,0xcd,0x6d,0x89,
0xb0
};
if (ret == 0) {
ret = ecc_encrypt_gcm_kat_vec(rng, ecAES_128_GCM, ecHKDF_SHA256,
enc_msg_128_hkdf, (word32)sizeof(enc_msg_128_hkdf));
}
#ifdef HAVE_X963_KDF
/* AES-128-GCM, X9.63-KDF-SHA256, SEC1 format */
{
WOLFSSL_SMALL_STACK_STATIC const byte enc_msg_128_x963[] = {
0x04,0x7b,0x1a,0x46,0x41,0x7c,0x5e,0x64,
0xb4,0x55,0x73,0x78,0xf1,0x7f,0xe9,0xbf,
0xd9,0x01,0xdb,0x1a,0x5d,0xef,0x96,0x1c,
0x78,0x58,0x1b,0x68,0x5f,0x5d,0xe4,0x40,
0xcd,0x8f,0xdf,0x88,0xc5,0x06,0xc1,0x64,
0x00,0x37,0x45,0xe0,0x6c,0xf0,0x61,0x70,
0xda,0x2d,0x65,0xff,0xd2,0x59,0x5b,0x73,
0x9d,0x4f,0x72,0x15,0x21,0xa5,0x54,0xbc,
0x80,0x2f,0x0d,0x83,0x64,0x0e,0x41,0x2b,
0x1e,0x61,0xbb,0x0c,0x98,0x37,0x0e,0xbe,
0xf4,0xb2,0xf3,0xae,0x07,0x20,0x88,0x79,
0xb3,0x08,0xca,0x73,0x2b,0xb3,0x26,0x8f,
0x2b,0x22,0x05,0x57,0x4f,0x50,0x04,0xc1,
0x51,0x9c,0xbb,0xb5,0xd2,0xad,0x3b,0x19,
0x1c,0x14,0xc0,0xd5,0x81,0x60,0x34,0x79,
0x04,0x26,0x18,0x20,0x2d,0xd7,0xda,0xa2,
0x31
};
if (ret == 0) {
ret = ecc_encrypt_gcm_kat_vec(rng, ecAES_128_GCM,
ecKDF_X963_SHA256, enc_msg_128_x963,
(word32)sizeof(enc_msg_128_x963));
}
}
#endif /* HAVE_X963_KDF */
#endif /* WOLFSSL_AES_128 */
return ret;
}
#endif /* GCM KAT guards */
#if defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC)
/* Minimal ECIES CryptoCb: with mode==1 it services the operation (forwarding to
* software after clearing devId) and records that it was invoked; with mode==0
* it returns CRYPTOCB_UNAVAILABLE so ECIES falls back to software. */
typedef struct EciesCbCtx {
int mode; /* 0 = force fallback, 1 = handle in callback */
int encryptInvoked; /* set when the callback services an ECIES encrypt */
int decryptInvoked; /* set when the callback services an ECIES decrypt */
} EciesCbCtx;
static int myEciesCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
EciesCbCtx* cbCtx = (EciesCbCtx*)ctx;
if (info->algo_type == WC_ALGO_TYPE_PK) {
if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
if (cbCtx->mode == 0)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
cbCtx->encryptInvoked = 1;
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
info->pk.eciesencrypt.privKey->devId = devIdArg;
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
if (cbCtx->mode == 0)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
cbCtx->decryptInvoked = 1;
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
}
}
return ret;
}
#define ECIES_CB_TEST_DEVID 0x45434945 /* 'ECIE' */
/* Every ECIES DEM cipher available in this build. The CryptoCb dispatch is
* whole-operation (cipher-agnostic), but we route each mode through the
* callback to prove the round-trip works for all of them. */
static const byte eciesCbModes[] = {
#if !defined(NO_AES) && defined(HAVE_AES_CBC)
#ifdef WOLFSSL_AES_128
ecAES_128_CBC,
#endif
#ifdef WOLFSSL_AES_256
ecAES_256_CBC,
#endif
#endif
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
#ifdef WOLFSSL_AES_128
ecAES_128_CTR,
#endif
#ifdef WOLFSSL_AES_256
ecAES_256_CTR,
#endif
#endif
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)
#ifdef WOLFSSL_AES_128
ecAES_128_GCM,
#endif
#ifdef WOLFSSL_AES_256
ecAES_256_GCM,
#endif
#endif
0 /* sentinel so the array is never zero-sized; skipped at runtime */
};
/* One callback round-trip for a specific DEM cipher. handleInCb selects whether
* the callback services the op (mode 1) or declines so software runs (mode 0).
* Verifies the plaintext round-trips and that the callback was/ wasn't used. */
static wc_test_ret_t ecies_cryptocb_roundtrip(WC_RNG* rng, EciesCbCtx* cbCtx,
ecc_key* userA, ecc_key* userB, byte encAlgo, int handleInCb)
{
wc_test_ret_t ret;
ecEncCtx* cliCtx = NULL;
ecEncCtx* srvCtx = NULL;
byte msg[32];
byte out[256];
byte plain[64];
word32 outSz = (word32)sizeof(out);
word32 plainSz = (word32)sizeof(plain);
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt;
ecc_key* decPub = NULL;
int i;
#ifdef WOLFSSL_ECIES_OLD
decPub = userA; /* OLD needs the sender's public key to decrypt */
#endif
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, rng);
srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, rng);
if (cliCtx == NULL || srvCtx == NULL) { ret = WC_TEST_RET_ENC_ERRNO; goto rt_done; }
ret = wc_ecc_ctx_set_algo(cliCtx, encAlgo, ecHKDF_SHA256, ecHMAC_SHA256);
if (ret == 0)
ret = wc_ecc_ctx_set_algo(srvCtx, encAlgo, ecHKDF_SHA256, ecHMAC_SHA256);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL) { ret = WC_TEST_RET_ENC_NC; goto rt_done; }
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx);
if (tmpSalt == NULL) { ret = WC_TEST_RET_ENC_NC; goto rt_done; }
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ret = wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt);
if (ret == 0)
ret = wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
cbCtx->mode = handleInCb;
cbCtx->encryptInvoked = 0;
cbCtx->decryptInvoked = 0;
ret = wc_ecc_encrypt(userA, userB, msg, sizeof(msg), out, &outSz, cliCtx);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
ret = wc_ecc_decrypt(userB, decPub, out, outSz, plain, &plainSz, srvCtx);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
if (plainSz != sizeof(msg) || XMEMCMP(plain, msg, sizeof(msg)) != 0) {
ret = WC_TEST_RET_ENC_NC; goto rt_done;
}
/* Both directions must be serviced by the callback when handleInCb==1, and
* neither when it's 0 (software ran). Checking them separately catches a
* silently-broken dispatch in one direction that a single flag would hide. */
if (cbCtx->encryptInvoked != (handleInCb ? 1 : 0) ||
cbCtx->decryptInvoked != (handleInCb ? 1 : 0))
ret = WC_TEST_RET_ENC_NC;
rt_done:
wc_ecc_ctx_free(cliCtx);
wc_ecc_ctx_free(srvCtx);
return ret;
}
/* Exercises the ECIES CryptoCb dispatch for every DEM cipher in the build, and
* for each: pass with the callback servicing the op, and a pass verifying
* software fallback on CRYPTOCB_UNAVAILABLE. */
static wc_test_ret_t ecc_encrypt_cryptocb_test(WC_RNG* rng)
{
wc_test_ret_t ret = 0;
ecc_key* userA = NULL;
ecc_key* userB = NULL;
int registered = 0;
int userAInit = 0, userBInit = 0;
int m, pass;
EciesCbCtx cbCtx;
XMEMSET(&cbCtx, 0, sizeof(cbCtx));
ret = wc_CryptoCb_RegisterDevice(ECIES_CB_TEST_DEVID, myEciesCryptoCb,
&cbCtx);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
registered = 1;
userA = (ecc_key*)XMALLOC(sizeof(*userA), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
userB = (ecc_key*)XMALLOC(sizeof(*userB), HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (userA == NULL || userB == NULL) {
ret = WC_TEST_RET_ENC_ERRNO;
goto cb_done;
}
/* Fresh keys owned by this test, routed to our callback via devId. */
ret = wc_ecc_init_ex(userA, HEAP_HINT, ECIES_CB_TEST_DEVID);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
userAInit = 1;
ret = wc_ecc_init_ex(userB, HEAP_HINT, ECIES_CB_TEST_DEVID);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
userBInit = 1;
/* Our callback only handles ECIES, so keygen falls back to software.
* Clear devId during make so keygen uses software directly, then restore
* for the ECIES ops. */
userA->devId = INVALID_DEVID;
userB->devId = INVALID_DEVID;
ret = wc_ecc_make_key(rng, ECC_KEYGEN_SIZE, userA);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
ret = wc_ecc_make_key(rng, ECC_KEYGEN_SIZE, userB);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ret = wc_ecc_set_rng(userA, rng);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
ret = wc_ecc_set_rng(userB, rng);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto cb_done; }
#endif
userA->devId = ECIES_CB_TEST_DEVID;
userB->devId = ECIES_CB_TEST_DEVID;
/* For each DEM cipher in the build: pass 1 = callback services the op,
* pass 0 = callback declines and software fallback runs. */
for (m = 0;
m < (int)(sizeof(eciesCbModes) / sizeof(eciesCbModes[0])) && ret == 0;
m++) {
if (eciesCbModes[m] == 0) /* sentinel entry */
continue;
for (pass = 1; pass >= 0 && ret == 0; pass--) {
ret = ecies_cryptocb_roundtrip(rng, &cbCtx, userA, userB,
eciesCbModes[m], pass);
}
}
cb_done:
if (userAInit)
wc_ecc_free(userA);
if (userBInit)
wc_ecc_free(userB);
XFREE(userA, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(userB, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
if (registered)
wc_CryptoCb_UnRegisterDevice(ECIES_CB_TEST_DEVID);
return ret;
}
#endif /* WOLF_CRYPTO_CB && !WOLFSSL_NO_MALLOC */
#endif /* !HAVE_FIPS || FIPS_VERSION_GE(5,3) */
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_encrypt_test(void)
@@ -45105,6 +45612,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_encrypt_test(void)
#if !defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))
if (ret == 0)
ret = ecc_encrypt_combos_test(&rng, userA, userB);
#if !defined(NO_AES) && defined(HAVE_AESGCM) && \
defined(HAVE_HKDF) && !defined(WOLFSSL_ECIES_OLD) && \
!defined(WOLFSSL_ECIES_ISO18033) && !defined(WOLFSSL_ECIES_GEN_IV) && \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE) && !defined(WOLFSSL_NO_MALLOC)
if (ret == 0)
ret = ecc_encrypt_gcm_kat(&rng);
#endif
#if defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC)
if (ret == 0)
ret = ecc_encrypt_cryptocb_test(&rng);
#endif
#endif /* !HAVE_FIPS || FIPS_VERSION_GE(5,3) */
done:
@@ -77258,6 +77776,27 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
info->pk.ecdh.private_key->devId = devIdArg;
#endif
}
#ifdef HAVE_ECC_ENCRYPT
else if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
/* set devId to invalid so the software path runs */
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
/* reset devId */
info->pk.eciesencrypt.privKey->devId = devIdArg;
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
}
#endif /* HAVE_ECC_ENCRYPT */
else if (info->pk.type == WC_PK_TYPE_EC_GET_SIZE) {
WC_DECLARE_VAR(tmpEcc, ecc_key, 1, NULL);
WC_ALLOC_VAR(tmpEcc, ecc_key, 1, NULL);
+28
View File
@@ -267,6 +267,27 @@ typedef struct wc_CryptoInfo {
* public point) */
} ecc_check_pub; /* distinct from ecc_check (priv-key cmp) */
#endif
#ifdef HAVE_ECC_ENCRYPT
struct {
ecc_key* privKey;
ecc_key* pubKey;
const byte* msg;
word32 msgSz;
byte* out;
word32* outSz;
ecEncCtx* ctx;
int compressed;
} eciesencrypt;
struct {
ecc_key* privKey;
ecc_key* pubKey;
const byte* msg;
word32 msgSz;
byte* out;
word32* outSz;
ecEncCtx* ctx;
} eciesdecrypt;
#endif /* HAVE_ECC_ENCRYPT */
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
struct {
@@ -811,6 +832,13 @@ WOLFSSL_LOCAL int wc_CryptoCb_EccMakePub(ecc_key* key, ecc_point* pubOut);
WOLFSSL_LOCAL int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder,
int checkPriv);
#endif
#ifdef HAVE_ECC_ENCRYPT
WOLFSSL_LOCAL int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx,
int compressed);
WOLFSSL_LOCAL int wc_CryptoCb_EciesDecrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
#endif
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
+15 -1
View File
@@ -1036,7 +1036,9 @@ enum ecEncAlgo {
ecAES_128_CBC = 1, /* default */
ecAES_256_CBC = 2,
ecAES_128_CTR = 3,
ecAES_256_CTR = 4
ecAES_256_CTR = 4,
ecAES_128_GCM = 5,
ecAES_256_GCM = 6
};
enum ecKdfAlgo {
@@ -1059,6 +1061,8 @@ enum {
IV_SIZE_64 = 8,
IV_SIZE_128 = 16,
ECC_MAX_IV_SIZE = 16,
AES_GCM_NONCE_SZ = 12, /* GCM IV/nonce length for ECIES DEM */
AES_GCM_TAG_SZ = 16, /* GCM authentication tag length */
EXCHANGE_SALT_SZ = 16,
EXCHANGE_INFO_SZ = 23
};
@@ -1087,6 +1091,16 @@ int wc_ecc_ctx_reset(ecEncCtx* ctx, WC_RNG* rng); /* reset for use again w/o al
WOLFSSL_API
int wc_ecc_ctx_set_algo(ecEncCtx* ctx, byte encAlgo, byte kdfAlgo,
byte macAlgo);
#ifdef WOLF_CRYPTO_CB
/* Accessors for crypto-callback backends; only built with WOLF_CRYPTO_CB. */
WOLFSSL_API
int wc_ecc_ctx_get_algo(ecEncCtx* ctx, byte* encAlgo, byte* kdfAlgo,
byte* macAlgo);
WOLFSSL_API
int wc_ecc_ctx_get_kdf_salt(ecEncCtx* ctx, const byte** salt, word32* sz);
WOLFSSL_API
int wc_ecc_ctx_get_info(ecEncCtx* ctx, const byte** info, word32* sz);
#endif /* WOLF_CRYPTO_CB */
WOLFSSL_API
const byte* wc_ecc_ctx_get_own_salt(ecEncCtx* ctx);
WOLFSSL_API
+6
View File
@@ -1625,6 +1625,12 @@ enum wc_PkType {
WC_PK_TYPE_ED25519_CHECK_KEY = 37,
#undef _WC_PK_TYPE_MAX
#define _WC_PK_TYPE_MAX WC_PK_TYPE_ED25519_CHECK_KEY
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT)
WC_PK_TYPE_ECIES_ENCRYPT = 38,
WC_PK_TYPE_ECIES_DECRYPT = 39,
#undef _WC_PK_TYPE_MAX
#define _WC_PK_TYPE_MAX WC_PK_TYPE_ECIES_DECRYPT
#endif
WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX
};