ECIES: allow compressed public keys

ECIES messages have a public key/point at start of the data.
It can be either uncompressed or compressed.
Adding support for decrypting and encrypting of compressed point.
pull/4802/head
Sean Parkinson 2022-01-27 12:10:59 +10:00
parent 9bbc5e07e6
commit b890a2f15d
4 changed files with 155 additions and 6 deletions

View File

@ -1539,6 +1539,7 @@ int wc_ecc_sig_size(ecc_key* key);
\endcode
\sa wc_ecc_encrypt
\sa wc_ecc_encrypt_ex
\sa wc_ecc_decrypt
*/
WOLFSSL_API
@ -1759,12 +1760,77 @@ int wc_ecc_ctx_set_info(ecEncCtx*, const byte* info, int sz);
}
\endcode
\sa wc_ecc_encrypt_ex
\sa wc_ecc_decrypt
*/
WOLFSSL_API
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
/*!
\ingroup ECC
\brief This function encrypts the given input message from msg
to out. This function takes an optional ctx object as parameter.
When supplied, encryption proceeds based on the ecEncCtx's
encAlgo, kdfAlgo, and macAlgo. If ctx is not supplied, processing
completes with the default algorithms, ecAES_128_CBC,
ecHKDF_SHA256 and ecHMAC_SHA256. This function requires that
the messages are padded according to the encryption type specified by ctx.
\return 0 Returned upon successfully encrypting the input message
\return BAD_FUNC_ARG Returned if privKey, pubKey, msg, msgSz, out,
or outSz are NULL, or the ctx object specifies an unsupported
encryption type
\return BAD_ENC_STATE_E Returned if the ctx object given is in a
state that is not appropriate for encryption
\return BUFFER_E Returned if the supplied output buffer is too
small to store the encrypted ciphertext
\return MEMORY_E Returned if there is an error allocating memory
for the shared secret key
\param privKey pointer to the ecc_key object containing the
private key to use for encryption
\param pubKey pointer to the ecc_key object containing the public
key of the peer with whom one wishes to communicate
\param msg pointer to the buffer holding the message to encrypt
\param msgSz size of the buffer to encrypt
\param out pointer to the buffer in which to store the encrypted
ciphertext
\param outSz pointer to a word32 object containing the available
size in the out buffer. Upon successfully encrypting the message,
holds the number of bytes written to the output buffer
\param ctx Optional: pointer to an ecEncCtx object specifying different
encryption algorithms to use
\param compressed Public key field is to be output in compressed format.
_Example_
\code
byte msg[] = { initialize with msg to encrypt. Ensure padded to block size };
byte out[sizeof(msg)];
word32 outSz = sizeof(out);
int ret;
ecc_key cli, serv;
// initialize cli with private key
// initialize serv with received public key
ecEncCtx* cliCtx, servCtx;
// initialize cliCtx and servCtx
// exchange salts
ret = wc_ecc_encrypt_ex(&cli, &serv, msg, sizeof(msg), out, &outSz, cliCtx,
1);
if(ret != 0) {
// error encrypting message
}
\endcode
\sa wc_ecc_encrypt
\sa wc_ecc_decrypt
*/
WOLFSSL_API
int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx, int compressed);
/*!
\ingroup ECC
@ -1822,6 +1888,7 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
\endcode
\sa wc_ecc_encrypt
\sa wc_ecc_encrypt_ex
*/
WOLFSSL_API
int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,

View File

@ -11928,8 +11928,8 @@ static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
ctx holds non default algos and inputs
msgSz should be the right size for encAlgo, i.e., already padded
return 0 on success */
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx, int compressed)
{
int ret = 0;
word32 blockSz = 0;
@ -11979,7 +11979,12 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
return ret;
#ifndef WOLFSSL_ECIES_OLD
pubKeySz = 1 + wc_ecc_size(privKey) * 2;
if (!compressed) {
pubKeySz = 1 + wc_ecc_size(privKey) * 2;
}
else {
pubKeySz = 1 + wc_ecc_size(privKey);
}
#endif
if (ctx->protocol == REQ_RESP_SERVER) {
@ -12027,7 +12032,7 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
if (ret != 0)
return ret;
}
ret = wc_ecc_export_x963(privKey, out, &pubKeySz);
ret = wc_ecc_export_x963_ex(privKey, out, &pubKeySz, compressed);
if (ret != 0)
return ret;
out += pubKeySz;
@ -12191,6 +12196,15 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
return ret;
}
/* ecc encrypt with shared secret run through kdf
ctx holds non default algos and inputs
msgSz should be the right size for encAlgo, i.e., already padded
return 0 on success */
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
{
return wc_ecc_encrypt_ex(privKey, pubKey, msg, msgSz, out, outSz, ctx, 0);
}
/* ecc decrypt with shared secret run through kdf
ctx holds non default algos and inputs
@ -12257,6 +12271,11 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
ret = ecc_public_key_size(privKey, &pubKeySz);
if (ret != 0)
return ret;
#ifdef HAVE_COMP_KEY
if ((msgSz > 1) && ((msg[0] == 0x02) || (msg[0] == 0x03))) {
pubKeySz = (pubKeySz / 2) + 1;
}
#endif
#endif
if (ctx->protocol == REQ_RESP_CLIENT) {

View File

@ -24642,6 +24642,66 @@ WOLFSSL_TEST_SUBROUTINE int ecc_encrypt_test(void)
ret = -10412; goto done;
}
#ifdef HAVE_COMP_KEY
/* Create new client and server contexts. */
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
/* let's verify message exchange works, A is client, B is server */
cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng);
if (cliCtx == NULL || srvCtx == NULL) {
ret = -10416; goto done;
}
/* get salt to send to peer */
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL) {
ret = -10417; goto done;
}
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx);
if (tmpSalt == NULL) {
ret = -10418; goto done;
}
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
/* in actual use, we'd get the peer's salt over the transport */
ret = wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt);
if (ret != 0)
goto done;
ret = wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt);
if (ret != 0)
goto done;
ret = wc_ecc_ctx_set_info(cliCtx, (byte*)"wolfSSL MSGE", 11);
if (ret != 0)
goto done;
ret = wc_ecc_ctx_set_info(srvCtx, (byte*)"wolfSSL MSGE", 11);
if (ret != 0)
goto done;
/* get encrypted msg (request) to send to B - compressed public key */
outSz = sizeof(out);
ret = wc_ecc_encrypt_ex(userA, userB, msg, sizeof(msg), out, &outSz, cliCtx,
1);
if (ret != 0)
goto done;
#ifndef WOLFSSL_ECIES_OLD
wc_ecc_free(tmpKey);
#endif
/* B decrypts msg (request) from A - out has a compressed public key */
plainSz = sizeof(plain);
ret = wc_ecc_decrypt(userB, tmpKey, out, outSz, plain, &plainSz, srvCtx);
if (ret != 0)
goto done;
if (XMEMCMP(plain, msg, sizeof(msg)) != 0) {
ret = -10419; goto done;
}
#endif /* HAVE_COMP_KEY */
#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
ret = ecc_encrypt_kat(&rng);
#endif

View File

@ -869,10 +869,13 @@ int wc_ecc_ctx_set_info(ecEncCtx* ctx, const byte* info, int sz);
WOLFSSL_API
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
WOLFSSL_API
int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx, int compressed);
WOLFSSL_API
int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
#endif /* HAVE_ECC_ENCRYPT */