To address the initial question "Is it possible to use ECC private key for encryption?"
Typically users maintain a private key and share their public key. The public key is mathematically entangled with the private key so messages encrypted with the public key can be decrypted with the private key. In this way the private key remains exactly that, private! It is not recommended to use a private key for encrypting ever. If you can justify your reason for wishing to do this by all means please explain. Happy to hear your reasoning. If however you are learning and just unsure then please avoid doing what you asked.
To address the statement about private key encryption for mutual authentication... I'm not sure how that will help to provide mutual authentication and I am genuinely curious what @comomind was talking about there. Here is a link about how SSL/TLS can solve the problem of mutual authentication:
(https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication)
For the second part of the question where wolfCrypt is concerned, the method (or function) in wolfSSL's wolfCrypt library is:
wc_ecc_encrypt
Here is the section from the manual describing this API and the arguments:
(https://www.wolfssl.com/wolfSSL/Docs-wolfssl-manual-18-14-wolfcrypt-api-ecc.html)
wc_ecc_encrypt
Synopsis:
include header: wolfssl/wolfcrypt/ecc.h
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
Description: 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 Values: 0: Returned upon successfully encrypting the input
message BAD_FUNC_ARG: Returned if privKey, pubKey, msg, msgSz, out, or
outSz are NULL, or the ctx object specifies an unsupported encryption
type BAD_ENC_STATE_E: Returned if the ctx object given is in a state
that is not appropriate for encryption BUFFER_E: Returned if the
supplied output buffer is too small to store the encrypted ciphertext
MEMORY_E: Returned if there is an error allocating memory for the
shared secret key
Parameters: privKey - pointer to the ecc_key object containing the
private key to use for encryption pubKey - pointer to the ecc_key
object containing the public key of the peer with whom one wishes to
communicate msg- pointer to the buffer holding the message to encrypt
msgSz - size of the buffer to encrypt out - pointer to the buffer in
which to store the encrypted ciphertext 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 ctx - Optional: pointer to an ecEncCtx object
specifying different encryption algorithms to use
Example:
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(&cli, &serv, msg, sizeof(msg), out, &outSz,
cliCtx);
if(ret != 0) { // error encrypting message }
See Also: wc_ecc_decrypt
Notice this API takes in both a public and private key, where the public key came from the peer and the private key is your own private key. This API will then use ECDH to generate a shared secret. The shared secret is what should be used for encrypting and decrypting. The party you are trying to talk to will also take your public key and his private key to generate his own shared-secret key. The shared secret is never sent over the wire by either party. See more on the topic of shared secret here: (https://crypto.stackexchange.com/questions/21169/how-does-ecdh-arrive-on-a-shared-secret)
TEST CASE:
(https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/test/test.c#L8701)
#ifdef HAVE_ECC_ENCRYPT
int ecc_encrypt_test(void)
{
WC_RNG rng;
int ret;
ecc_key userA, userB;
byte msg[48];
byte plain[48];
byte out[80];
word32 outSz = sizeof(out);
word32 plainSz = sizeof(plain);
int i;
ret = wc_InitRng(&rng);
if (ret != 0)
return -3001;
wc_ecc_init(&userA);
wc_ecc_init(&userB);
ret = wc_ecc_make_key(&rng, 32, &userA);
ret += wc_ecc_make_key(&rng, 32, &userB);
if (ret != 0)
return -3002;
for (i = 0; i < 48; i++)
msg[i] = i;
/* encrypt msg to send to userB */
ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL);
if (ret != 0)
return -3003;
/* userB decrypt the message received from userA */
ret = wc_ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, NULL);
if (ret != 0)
return -3004;
if (XMEMCMP(plain, msg, sizeof(msg)) != 0)
return -3005;
{ /* let's verify message exchange works, A is client, B is server */
ecEncCtx* cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
ecEncCtx* srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng);
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt;
if (cliCtx == NULL || srvCtx == NULL)
return -3006;
/* get salt to send to peer */
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL)
return -3007;
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx);
if (tmpSalt == NULL)
return -3007;
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);
ret += wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt);
ret += wc_ecc_ctx_set_info(cliCtx, (byte*)"wolfSSL MSGE", 11);
ret += wc_ecc_ctx_set_info(srvCtx, (byte*)"wolfSSL MSGE", 11);
if (ret != 0)
return -3008;
/* get encrypted msg (request) to send to B */
outSz = sizeof(out);
ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz,cliCtx);
if (ret != 0)
return -3009;
/* B decrypts msg (request) from A */
plainSz = sizeof(plain);
ret = wc_ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, srvCtx);
if (ret != 0)
return -3010;
if (XMEMCMP(plain, msg, sizeof(msg)) != 0)
return -3011;
{
/* msg2 (response) from B to A */
byte msg2[48];
byte plain2[48];
byte out2[80];
word32 outSz2 = sizeof(out2);
word32 plainSz2 = sizeof(plain2);
for (i = 0; i < 48; i++)
msg2[i] = i+48;
/* get encrypted msg (response) to send to B */
ret = wc_ecc_encrypt(&userB, &userA, msg2, sizeof(msg2), out2,
&outSz2, srvCtx);
if (ret != 0)
return -3012;
/* A decrypts msg (response) from B */
ret = wc_ecc_decrypt(&userA, &userB, out2, outSz2, plain2, &plainSz2,
cliCtx);
if (ret != 0)
return -3013;
if (XMEMCMP(plain2, msg2, sizeof(msg2)) != 0)
return -3014;
}
/* cleanup */
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
}
/* cleanup */
wc_ecc_free(&userB);
wc_ecc_free(&userA);
wc_FreeRng(&rng);
return 0;
}
#endif /* HAVE_ECC_ENCRYPT */