forked from wolfSSL/wolfssl
add ecc encrypt secure message exchange, hide ecEncCtx
This commit is contained in:
@ -3510,33 +3510,189 @@ void ecc_fp_free(void)
|
|||||||
|
|
||||||
#ifdef HAVE_ECC_ENCRYPT
|
#ifdef HAVE_ECC_ENCRYPT
|
||||||
|
|
||||||
/* init and set defaults, just holders */
|
|
||||||
void ecc_encrypt_init_options(ecEncOptions* options)
|
|
||||||
{
|
|
||||||
if (options) {
|
|
||||||
XMEMSET(options, 0, sizeof(ecEncOptions));
|
|
||||||
|
|
||||||
options->encAlgo = ecAES_128_CBC;
|
enum ecCliState {
|
||||||
options->kdfAlgo = ecHKDF_SHA256;
|
ecCLI_INIT = 1,
|
||||||
options->macAlgo = ecHMAC_SHA256;
|
ecCLI_SALT_GET = 2,
|
||||||
|
ecCLI_SALT_SET = 3,
|
||||||
|
ecCLI_SENT_REQ = 4,
|
||||||
|
ecCLI_RECV_RESP = 5,
|
||||||
|
ecCLI_BAD_STATE = 99
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ecSrvState {
|
||||||
|
ecSRV_INIT = 1,
|
||||||
|
ecSRV_SALT_GET = 2,
|
||||||
|
ecSRV_SALT_SET = 3,
|
||||||
|
ecSRV_RECV_REQ = 4,
|
||||||
|
ecSRV_SENT_RESP = 5,
|
||||||
|
ecSRV_BAD_STATE = 99
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ecEncCtx {
|
||||||
|
byte* kdfSalt; /* optional salt for kdf */
|
||||||
|
byte* kdfInfo; /* optional info for kdf */
|
||||||
|
byte* macSalt; /* optional salt for mac */
|
||||||
|
word32 kdfSaltSz; /* size of kdfSalt */
|
||||||
|
word32 kdfInfoSz; /* size of kdfInfo */
|
||||||
|
word32 macSaltSz; /* size of macSalt */
|
||||||
|
byte clientSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */
|
||||||
|
byte serverSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */
|
||||||
|
byte encAlgo; /* which encryption type */
|
||||||
|
byte kdfAlgo; /* which key derivation function type */
|
||||||
|
byte macAlgo; /* which mac function type */
|
||||||
|
byte protocol; /* are we REQ_RESP client or server ? */
|
||||||
|
byte cliSt; /* protocol state, for sanity checks */
|
||||||
|
byte srvSt; /* protocol state, for sanity checks */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const byte* ecc_ctx_get_own_salt(ecEncCtx* ctx)
|
||||||
|
{
|
||||||
|
if (ctx == NULL || ctx->protocol == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ctx->protocol == REQ_RESP_CLIENT) {
|
||||||
|
if (ctx->cliSt == ecCLI_INIT) {
|
||||||
|
ctx->cliSt = ecCLI_SALT_GET;
|
||||||
|
return ctx->clientSalt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx->cliSt = ecCLI_BAD_STATE;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (ctx->protocol == REQ_RESP_SERVER) {
|
||||||
|
if (ctx->srvSt == ecSRV_INIT) {
|
||||||
|
ctx->srvSt = ecSRV_SALT_GET;
|
||||||
|
return ctx->serverSalt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx->srvSt = ecSRV_BAD_STATE;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char* exchange_info = "Secure Message Exchange";
|
||||||
|
|
||||||
|
int ecc_ctx_set_peer_salt(ecEncCtx* ctx, const byte* salt)
|
||||||
|
{
|
||||||
|
byte tmp[EXCHANGE_SALT_SZ/2];
|
||||||
|
int halfSz = EXCHANGE_SALT_SZ/2;
|
||||||
|
|
||||||
|
if (ctx == NULL || ctx->protocol == 0 || salt == NULL)
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
|
if (ctx->protocol == REQ_RESP_CLIENT) {
|
||||||
|
XMEMCPY(ctx->serverSalt, salt, EXCHANGE_SALT_SZ);
|
||||||
|
if (ctx->cliSt == ecCLI_SALT_GET)
|
||||||
|
ctx->cliSt = ecCLI_SALT_SET;
|
||||||
|
else {
|
||||||
|
ctx->cliSt = ecCLI_BAD_STATE;
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
XMEMCPY(ctx->clientSalt, salt, EXCHANGE_SALT_SZ);
|
||||||
|
if (ctx->srvSt == ecSRV_SALT_GET)
|
||||||
|
ctx->srvSt = ecSRV_SALT_SET;
|
||||||
|
else {
|
||||||
|
ctx->srvSt = ecSRV_BAD_STATE;
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mix half and half */
|
||||||
|
/* tmp stores 2nd half of client before overwrite */
|
||||||
|
XMEMCPY(tmp, ctx->clientSalt + halfSz, halfSz);
|
||||||
|
XMEMCPY(ctx->clientSalt + halfSz, ctx->serverSalt, halfSz);
|
||||||
|
XMEMCPY(ctx->serverSalt, tmp, halfSz);
|
||||||
|
|
||||||
|
ctx->kdfSalt = ctx->clientSalt;
|
||||||
|
ctx->kdfSaltSz = EXCHANGE_SALT_SZ;
|
||||||
|
|
||||||
|
ctx->macSalt = ctx->serverSalt;
|
||||||
|
ctx->macSaltSz = EXCHANGE_SALT_SZ;
|
||||||
|
|
||||||
|
ctx->kdfInfo = (byte*)exchange_info;
|
||||||
|
ctx->kdfInfoSz = EXCHANGE_INFO_SZ;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ecc_ctx_set_salt(ecEncCtx* ctx, int flags, RNG* rng)
|
||||||
|
{
|
||||||
|
byte* saltBuffer = NULL;
|
||||||
|
|
||||||
|
if (ctx == NULL || rng == NULL || flags == 0)
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
|
saltBuffer = (flags == REQ_RESP_CLIENT) ? ctx->clientSalt : ctx->serverSalt;
|
||||||
|
RNG_GenerateBlock(rng, saltBuffer, EXCHANGE_SALT_SZ);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ecc_ctx_init(ecEncCtx* ctx, int flags)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
XMEMSET(ctx, 0, sizeof(ecEncCtx));
|
||||||
|
|
||||||
|
ctx->encAlgo = ecAES_128_CBC;
|
||||||
|
ctx->kdfAlgo = ecHKDF_SHA256;
|
||||||
|
ctx->macAlgo = ecHMAC_SHA256;
|
||||||
|
ctx->protocol = (byte)flags;
|
||||||
|
|
||||||
|
if (flags == REQ_RESP_CLIENT)
|
||||||
|
ctx->cliSt = ecCLI_INIT;
|
||||||
|
if (flags == REQ_RESP_SERVER)
|
||||||
|
ctx->srvSt = ecSRV_INIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* alloc/init and set defaults, return new Context */
|
||||||
|
ecEncCtx* ecc_ctx_new(int flags, RNG* rng)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
ecEncCtx* ctx = (ecEncCtx*)XMALLOC(sizeof(ecEncCtx), 0, DYNAMIC_TYPE_ECC);
|
||||||
|
|
||||||
|
ecc_ctx_init(ctx, flags);
|
||||||
|
|
||||||
|
if (ctx && flags)
|
||||||
|
ret = ecc_ctx_set_salt(ctx, flags, rng);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
ecc_ctx_free(ctx);
|
||||||
|
ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* free any resources, clear any keys */
|
/* free any resources, clear any keys */
|
||||||
void ecc_encrypt_free_options(ecEncOptions* options)
|
void ecc_ctx_free(ecEncCtx* ctx)
|
||||||
{
|
{
|
||||||
if (options) {
|
if (ctx) {
|
||||||
XMEMSET(options, 0, sizeof(ecEncOptions));
|
XMEMSET(ctx, 0, sizeof(ecEncCtx));
|
||||||
|
XFREE(ctx, 0, DYNAMIC_TYPE_ECC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ecc_get_key_sizes(ecEncOptions* options, int* encKeySz, int* ivSz,
|
static int ecc_get_key_sizes(ecEncCtx* ctx, int* encKeySz, int* ivSz,
|
||||||
int* keysLen, word32* digestSz, word32* blockSz)
|
int* keysLen, word32* digestSz, word32* blockSz)
|
||||||
{
|
{
|
||||||
if (options) {
|
if (ctx) {
|
||||||
switch (options->encAlgo) {
|
switch (ctx->encAlgo) {
|
||||||
case ecAES_128_CBC:
|
case ecAES_128_CBC:
|
||||||
*encKeySz = KEY_SIZE_128;
|
*encKeySz = KEY_SIZE_128;
|
||||||
*ivSz = IV_SIZE_64;
|
*ivSz = IV_SIZE_64;
|
||||||
@ -3546,7 +3702,7 @@ static int ecc_get_key_sizes(ecEncOptions* options, int* encKeySz, int* ivSz,
|
|||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (options->macAlgo) {
|
switch (ctx->macAlgo) {
|
||||||
case ecHMAC_SHA256:
|
case ecHMAC_SHA256:
|
||||||
*digestSz = SHA256_DIGEST_SIZE;
|
*digestSz = SHA256_DIGEST_SIZE;
|
||||||
break;
|
break;
|
||||||
@ -3563,22 +3719,23 @@ static int ecc_get_key_sizes(ecEncOptions* options, int* encKeySz, int* ivSz,
|
|||||||
|
|
||||||
|
|
||||||
/* ecc encrypt with shared secret run through kdf
|
/* ecc encrypt with shared secret run through kdf
|
||||||
options holds non default algos and inputs
|
ctx holds non default algos and inputs
|
||||||
msgSz should be the right size for encAlgo, i.e., already padded
|
msgSz should be the right size for encAlgo, i.e., already padded
|
||||||
return 0 on success */
|
return 0 on success */
|
||||||
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||||
word32 msgSz, byte* out, word32* outSz, ecEncOptions* opts)
|
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
word32 blockSz;
|
word32 blockSz;
|
||||||
word32 digestSz;
|
word32 digestSz;
|
||||||
ecEncOptions options;
|
ecEncCtx localCtx;
|
||||||
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
|
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
|
||||||
byte keys[ECC_BUFSIZE]; /* max size */
|
byte keys[ECC_BUFSIZE]; /* max size */
|
||||||
word32 sharedSz = sizeof(sharedSecret);
|
word32 sharedSz = sizeof(sharedSecret);
|
||||||
int keysLen;
|
int keysLen;
|
||||||
int encKeySz;
|
int encKeySz;
|
||||||
int ivSz;
|
int ivSz;
|
||||||
|
int offset; /* keys offset if doing msg exchange */
|
||||||
byte* encKey;
|
byte* encKey;
|
||||||
byte* encIv;
|
byte* encIv;
|
||||||
byte* macKey;
|
byte* macKey;
|
||||||
@ -3587,19 +3744,37 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
outSz == NULL)
|
outSz == NULL)
|
||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
if (opts)
|
if (ctx == NULL) { /* use defaults */
|
||||||
options = *opts;
|
ecc_ctx_init(&localCtx, 0);
|
||||||
else {
|
ctx = &localCtx;
|
||||||
ecc_encrypt_init_options(&options); /* defaults */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ecc_get_key_sizes(&options, &encKeySz, &ivSz, &keysLen, &digestSz,
|
ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
|
||||||
&blockSz);
|
&blockSz);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (ctx->protocol == REQ_RESP_SERVER) {
|
||||||
|
offset = keysLen;
|
||||||
|
keysLen *= 2;
|
||||||
|
|
||||||
|
if (ctx->srvSt != ecSRV_RECV_REQ)
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
|
||||||
|
ctx->srvSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
|
||||||
|
}
|
||||||
|
else if (ctx->protocol == REQ_RESP_CLIENT) {
|
||||||
|
if (ctx->cliSt != ecCLI_SALT_SET)
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
|
||||||
|
ctx->cliSt = ecCLI_SENT_REQ; /* only do this once */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keysLen > (int)sizeof(keys))
|
||||||
|
return BUFFER_E;
|
||||||
|
|
||||||
if ( (msgSz%blockSz) != 0)
|
if ( (msgSz%blockSz) != 0)
|
||||||
return BAD_FUNC_ARG;
|
return BAD_PADDING_E;
|
||||||
|
|
||||||
if (*outSz < (msgSz + digestSz))
|
if (*outSz < (msgSz + digestSz))
|
||||||
return BUFFER_E;
|
return BUFFER_E;
|
||||||
@ -3608,11 +3783,11 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
switch (options.kdfAlgo) {
|
switch (ctx->kdfAlgo) {
|
||||||
case ecHKDF_SHA256 :
|
case ecHKDF_SHA256 :
|
||||||
ret = HKDF(SHA256, sharedSecret, sharedSz, options.kdfSalt,
|
ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
|
||||||
options.kdfSaltSz, options.kdfInfo,
|
ctx->kdfSaltSz, ctx->kdfInfo,
|
||||||
options.kdfInfoSz, keys, keysLen);
|
ctx->kdfInfoSz, keys, keysLen);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
@ -3621,11 +3796,11 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
encKey = keys;
|
encKey = keys + offset;
|
||||||
encIv = encKey + encKeySz;
|
encIv = encKey + encKeySz;
|
||||||
macKey = encKey + encKeySz + ivSz;
|
macKey = encKey + encKeySz + ivSz;
|
||||||
|
|
||||||
switch (options.encAlgo) {
|
switch (ctx->encAlgo) {
|
||||||
case ecAES_128_CBC:
|
case ecAES_128_CBC:
|
||||||
{
|
{
|
||||||
Aes aes;
|
Aes aes;
|
||||||
@ -3642,7 +3817,7 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (options.macAlgo) {
|
switch (ctx->macAlgo) {
|
||||||
case ecHMAC_SHA256:
|
case ecHMAC_SHA256:
|
||||||
{
|
{
|
||||||
Hmac hmac;
|
Hmac hmac;
|
||||||
@ -3650,7 +3825,7 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
HmacUpdate(&hmac, out, msgSz);
|
HmacUpdate(&hmac, out, msgSz);
|
||||||
HmacUpdate(&hmac, options.macSalt, options.macSaltSz);
|
HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
|
||||||
HmacFinal(&hmac, out+msgSz);
|
HmacFinal(&hmac, out+msgSz);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3665,19 +3840,23 @@ int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ecc decrypt with shared secret run through kdf
|
||||||
|
ctx holds non default algos and inputs
|
||||||
|
return 0 on success */
|
||||||
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||||
word32 msgSz, byte* out, word32* outSz, ecEncOptions* opts)
|
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
word32 blockSz;
|
word32 blockSz;
|
||||||
word32 digestSz;
|
word32 digestSz;
|
||||||
ecEncOptions options;
|
ecEncCtx localCtx;
|
||||||
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
|
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
|
||||||
byte keys[ECC_BUFSIZE]; /* max size */
|
byte keys[ECC_BUFSIZE]; /* max size */
|
||||||
word32 sharedSz = sizeof(sharedSecret);
|
word32 sharedSz = sizeof(sharedSecret);
|
||||||
int keysLen;
|
int keysLen;
|
||||||
int encKeySz;
|
int encKeySz;
|
||||||
int ivSz;
|
int ivSz;
|
||||||
|
int offset; /* in case using msg exchange */
|
||||||
byte* encKey;
|
byte* encKey;
|
||||||
byte* encIv;
|
byte* encIv;
|
||||||
byte* macKey;
|
byte* macKey;
|
||||||
@ -3686,19 +3865,37 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
outSz == NULL)
|
outSz == NULL)
|
||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
|
|
||||||
if (opts)
|
if (ctx == NULL) { /* use defaults */
|
||||||
options = *opts;
|
ecc_ctx_init(&localCtx, 0);
|
||||||
else {
|
ctx = &localCtx;
|
||||||
ecc_encrypt_init_options(&options); /* defaults */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ecc_get_key_sizes(&options, &encKeySz, &ivSz, &keysLen, &digestSz,
|
ret = ecc_get_key_sizes(ctx, &encKeySz, &ivSz, &keysLen, &digestSz,
|
||||||
&blockSz);
|
&blockSz);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (ctx->protocol == REQ_RESP_CLIENT) {
|
||||||
|
offset = keysLen;
|
||||||
|
keysLen *= 2;
|
||||||
|
|
||||||
|
if (ctx->cliSt != ecCLI_SENT_REQ)
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
|
||||||
|
ctx->cliSt = ecSRV_BAD_STATE; /* we're done no more ops allowed */
|
||||||
|
}
|
||||||
|
else if (ctx->protocol == REQ_RESP_SERVER) {
|
||||||
|
if (ctx->srvSt != ecSRV_SALT_SET)
|
||||||
|
return BAD_ENC_STATE_E;
|
||||||
|
|
||||||
|
ctx->srvSt = ecSRV_RECV_REQ; /* only do this once */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keysLen > (int)sizeof(keys))
|
||||||
|
return BUFFER_E;
|
||||||
|
|
||||||
if ( ((msgSz-digestSz) % blockSz) != 0)
|
if ( ((msgSz-digestSz) % blockSz) != 0)
|
||||||
return BAD_FUNC_ARG;
|
return BAD_PADDING_E;
|
||||||
|
|
||||||
if (*outSz < (msgSz - digestSz))
|
if (*outSz < (msgSz - digestSz))
|
||||||
return BUFFER_E;
|
return BUFFER_E;
|
||||||
@ -3707,11 +3904,11 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
switch (options.kdfAlgo) {
|
switch (ctx->kdfAlgo) {
|
||||||
case ecHKDF_SHA256 :
|
case ecHKDF_SHA256 :
|
||||||
ret = HKDF(SHA256, sharedSecret, sharedSz, options.kdfSalt,
|
ret = HKDF(SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
|
||||||
options.kdfSaltSz, options.kdfInfo,
|
ctx->kdfSaltSz, ctx->kdfInfo,
|
||||||
options.kdfInfoSz, keys, keysLen);
|
ctx->kdfInfoSz, keys, keysLen);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
break;
|
break;
|
||||||
@ -3720,11 +3917,11 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
encKey = keys;
|
encKey = keys + offset;
|
||||||
encIv = encKey + encKeySz;
|
encIv = encKey + encKeySz;
|
||||||
macKey = encKey + encKeySz + ivSz;
|
macKey = encKey + encKeySz + ivSz;
|
||||||
|
|
||||||
switch (options.macAlgo) {
|
switch (ctx->macAlgo) {
|
||||||
case ecHMAC_SHA256:
|
case ecHMAC_SHA256:
|
||||||
{
|
{
|
||||||
byte verify[SHA256_DIGEST_SIZE];
|
byte verify[SHA256_DIGEST_SIZE];
|
||||||
@ -3733,7 +3930,7 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
HmacUpdate(&hmac, msg, msgSz-digestSz);
|
HmacUpdate(&hmac, msg, msgSz-digestSz);
|
||||||
HmacUpdate(&hmac, options.macSalt, options.macSaltSz);
|
HmacUpdate(&hmac, ctx->macSalt, ctx->macSaltSz);
|
||||||
HmacFinal(&hmac, verify);
|
HmacFinal(&hmac, verify);
|
||||||
|
|
||||||
if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) {
|
if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) {
|
||||||
@ -3746,7 +3943,7 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|||||||
return BAD_FUNC_ARG;
|
return BAD_FUNC_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (options.encAlgo) {
|
switch (ctx->encAlgo) {
|
||||||
case ecAES_128_CBC:
|
case ecAES_128_CBC:
|
||||||
{
|
{
|
||||||
Aes aes;
|
Aes aes;
|
||||||
|
@ -323,6 +323,14 @@ void CTaoCryptErrorString(int error, char* buffer)
|
|||||||
XSTRNCPY(buffer, "ASN OCSP sig error, confirm failure", max);
|
XSTRNCPY(buffer, "ASN OCSP sig error, confirm failure", max);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BAD_ENC_STATE_E:
|
||||||
|
XSTRNCPY(buffer, "Bad ecc encrypt state operation", max);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BAD_PADDING_E:
|
||||||
|
XSTRNCPY(buffer, "Bad padding, message wrong length", max);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
XSTRNCPY(buffer, "unknown error number", max);
|
XSTRNCPY(buffer, "unknown error number", max);
|
||||||
|
|
||||||
|
@ -3628,12 +3628,12 @@ int ecc_encrypt_test(void)
|
|||||||
for (i = 0; i < 48; i++)
|
for (i = 0; i < 48; i++)
|
||||||
msg[i] = i;
|
msg[i] = i;
|
||||||
|
|
||||||
/* send encrypted msg to B */
|
/* encrypt msg to B */
|
||||||
ret = ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL);
|
ret = ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return -3003;
|
return -3003;
|
||||||
|
|
||||||
/* decrypted msg to B */
|
/* decrypt msg from A */
|
||||||
ret = ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, NULL);
|
ret = ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, NULL);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return -3004;
|
return -3004;
|
||||||
@ -3641,6 +3641,84 @@ int ecc_encrypt_test(void)
|
|||||||
if (memcmp(plain, msg, sizeof(msg)) != 0)
|
if (memcmp(plain, msg, sizeof(msg)) != 0)
|
||||||
return -3005;
|
return -3005;
|
||||||
|
|
||||||
|
|
||||||
|
{ /* let's verify message exchange works, A is client, B is server */
|
||||||
|
ecEncCtx* cliCtx = ecc_ctx_new(REQ_RESP_CLIENT, &rng);
|
||||||
|
ecEncCtx* srvCtx = 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 = ecc_ctx_get_own_salt(cliCtx);
|
||||||
|
if (tmpSalt == NULL)
|
||||||
|
return -3007;
|
||||||
|
memcpy(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
|
||||||
|
|
||||||
|
tmpSalt = ecc_ctx_get_own_salt(srvCtx);
|
||||||
|
if (tmpSalt == NULL)
|
||||||
|
return -3007;
|
||||||
|
memcpy(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
|
||||||
|
|
||||||
|
/* in actual use, we'd get the peer's salt over the transport */
|
||||||
|
ret = ecc_ctx_set_peer_salt(cliCtx, srvSalt);
|
||||||
|
ret += ecc_ctx_set_peer_salt(srvCtx, cliSalt);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return -3008;
|
||||||
|
|
||||||
|
/* get encrypted msg (request) to send to B */
|
||||||
|
outSz = sizeof(out);
|
||||||
|
ret = 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 = ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, srvCtx);
|
||||||
|
if (ret != 0)
|
||||||
|
return -3010;
|
||||||
|
|
||||||
|
if (memcmp(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 = ecc_encrypt(&userB, &userA, msg2, sizeof(msg2), out2,
|
||||||
|
&outSz2, srvCtx);
|
||||||
|
if (ret != 0)
|
||||||
|
return -3012;
|
||||||
|
|
||||||
|
/* A decrypts msg (response) from B */
|
||||||
|
ret = ecc_decrypt(&userA, &userB, out2, outSz2, plain2, &plainSz2,
|
||||||
|
cliCtx);
|
||||||
|
if (ret != 0)
|
||||||
|
return -3013;
|
||||||
|
|
||||||
|
if (memcmp(plain2, msg2, sizeof(msg2)) != 0)
|
||||||
|
return -3014;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
ecc_ctx_free(srvCtx);
|
||||||
|
ecc_ctx_free(cliCtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
ecc_free(&userB);
|
ecc_free(&userB);
|
||||||
ecc_free(&userA);
|
ecc_free(&userA);
|
||||||
|
|
||||||
|
@ -119,6 +119,7 @@ CYASSL_API
|
|||||||
int ecc_sig_size(ecc_key* key);
|
int ecc_sig_size(ecc_key* key);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_ECC_ENCRYPT
|
||||||
/* ecc encrypt */
|
/* ecc encrypt */
|
||||||
|
|
||||||
enum ecEncAlgo {
|
enum ecEncAlgo {
|
||||||
@ -137,34 +138,39 @@ enum ecMacAlgo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_SIZE_128 = 16,
|
KEY_SIZE_128 = 16,
|
||||||
KEY_SIZE_256 = 32,
|
KEY_SIZE_256 = 32,
|
||||||
IV_SIZE_64 = 8
|
IV_SIZE_64 = 8,
|
||||||
|
EXCHANGE_SALT_SZ = 16,
|
||||||
|
EXCHANGE_INFO_SZ = 23
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ecEncOptions {
|
enum ecFlags {
|
||||||
byte encAlgo; /* which encryption type */
|
REQ_RESP_CLIENT = 1,
|
||||||
byte kdfAlgo; /* which key derivation function type */
|
REQ_RESP_SERVER = 2
|
||||||
byte macAlgo; /* which mac function type */
|
};
|
||||||
byte* kdfSalt; /* optional salt for kdf */
|
|
||||||
byte* kdfInfo; /* optional info for kdf */
|
|
||||||
byte* macSalt; /* optional salt for mac */
|
typedef struct ecEncCtx ecEncCtx;
|
||||||
word32 kdfSaltSz; /* size of kdfSalt */
|
|
||||||
word32 kdfInfoSz; /* size of kdfInfo */
|
|
||||||
word32 macSaltSz; /* size of macSalt */
|
|
||||||
} ecEncOptions;
|
|
||||||
|
|
||||||
CYASSL_API
|
CYASSL_API
|
||||||
void ecc_encrypt_init_options(ecEncOptions*); /* init and set to defaults */
|
ecEncCtx* ecc_ctx_new(int flags, RNG* rng);
|
||||||
CYASSL_API
|
CYASSL_API
|
||||||
void ecc_encrypt_free_options(ecEncOptions*); /* release/clear options */
|
void ecc_ctx_free(ecEncCtx*);
|
||||||
|
|
||||||
|
CYASSL_API
|
||||||
|
const byte* ecc_ctx_get_own_salt(ecEncCtx*);
|
||||||
|
CYASSL_API
|
||||||
|
int ecc_ctx_set_peer_salt(ecEncCtx*, const byte* salt);
|
||||||
|
|
||||||
CYASSL_API
|
CYASSL_API
|
||||||
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||||
word32 msgSz, byte* out, word32* outSz, ecEncOptions* options);
|
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
|
||||||
CYASSL_API
|
CYASSL_API
|
||||||
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
||||||
word32 msgSz, byte* out, word32* outSz, ecEncOptions* options);
|
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
|
||||||
|
|
||||||
|
#endif /* HAVE_ECC_ENCRYPT */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -114,6 +114,9 @@ enum {
|
|||||||
ASN_CRL_NO_SIGNER_E = -190, /* ASN CRL no signer to confirm failure */
|
ASN_CRL_NO_SIGNER_E = -190, /* ASN CRL no signer to confirm failure */
|
||||||
ASN_OCSP_CONFIRM_E = -191, /* ASN OCSP signature confirm failure */
|
ASN_OCSP_CONFIRM_E = -191, /* ASN OCSP signature confirm failure */
|
||||||
|
|
||||||
|
BAD_ENC_STATE_E = -192, /* Bad ecc enc state operation */
|
||||||
|
BAD_PADDING_E = -193, /* Bad padding, msg not correct length */
|
||||||
|
|
||||||
MIN_CODE_E = -200 /* errors -101 - -199 */
|
MIN_CODE_E = -200 /* errors -101 - -199 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user