add basic ecc encrypt/decrypt

This commit is contained in:
toddouska
2013-11-07 15:59:31 -08:00
parent fb8c3e0c75
commit 554adff672
4 changed files with 402 additions and 1 deletions

View File

@@ -595,10 +595,35 @@ AC_ARG_ENABLE([fpecc],
if test "$ENABLED_FPECC" = "yes"
then
if test "$ENABLED_ECC" = "no"
then
AC_MSG_ERROR([cannot enable fpecc without enabling ecc.])
fi
AM_CFLAGS="$AM_CFLAGS -DFP_ECC"
fi
# ECC encrypt
AC_ARG_ENABLE([eccencrypt],
[ --enable-eccencrypt Enable ECC encrypt (default: disabled)],
[ ENABLED_ECC_ENCRYPT=$enableval ],
[ ENABLED_ECC_ENCRYPT=no ]
)
if test "$ENABLED_ECC_ENCRYPT" = "yes"
then
if test "$ENABLED_ECC" = "no"
then
AC_MSG_ERROR([cannot enable eccencrypt without enabling ecc.])
fi
if test "$ENABLED_HKDF" = "no"
then
AC_MSG_ERROR([cannot enable eccencrypt without enabling hkdf.])
fi
AM_CFLAGS="$AM_CFLAGS -DHAVE_ECC_ENCRYPT"
fi
# PSK
AC_ARG_ENABLE([psk],
[ --enable-psk Enable PSK (default: disabled)],
@@ -1522,6 +1547,7 @@ echo " * certgen: $ENABLED_CERTGEN"
echo " * HC-128: $ENABLED_HC128"
echo " * RABBIT: $ENABLED_RABBIT"
echo " * PWDBASED: $ENABLED_PWDBASED"
echo " * HKDF: $ENABLED_HKDF"
echo " * MD4: $ENABLED_MD4"
echo " * PSK: $ENABLED_PSK"
echo " * LEANPSK: $ENABLED_LEANPSK"
@@ -1530,6 +1556,7 @@ echo " * DSA: $ENABLED_DSA"
echo " * DH: $ENABLED_DH"
echo " * ECC: $ENABLED_ECC"
echo " * FPECC: $ENABLED_FPECC"
echo " * ECC_ENCRYPT: $ENABLED_ECC_ENCRYPT"
echo " * ASN: $ENABLED_ASN"
echo " * CODING: $ENABLED_CODING"
echo " * MEMORY: $ENABLED_MEMORY"

View File

@@ -33,6 +33,11 @@
#include <cyassl/ctaocrypt/asn.h>
#include <cyassl/ctaocrypt/error.h>
#ifdef HAVE_ECC_ENCRYPT
#include <cyassl/ctaocrypt/hmac.h>
#include <cyassl/ctaocrypt/aes.h>
#endif
/* map
@@ -3484,6 +3489,269 @@ void ecc_fp_free(void)
}
#endif /* FP_ECC */
#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;
options->kdfAlgo = ecHKDF_SHA256;
options->macAlgo = ecHMAC_SHA256;
}
}
/* free any resources, clear any keys */
void ecc_encrypt_free_options(ecEncOptions* options)
{
if (options) {
XMEMSET(options, 0, sizeof(ecEncOptions));
}
}
static int ecc_get_key_sizes(ecEncOptions* options, int* encKeySz, int* ivSz,
int* keysLen, word32* digestSz, word32* blockSz)
{
if (options) {
switch (options->encAlgo) {
case ecAES_128_CBC:
*encKeySz = KEY_SIZE_128;
*ivSz = IV_SIZE_64;
*blockSz = AES_BLOCK_SIZE;
break;
default:
return BAD_FUNC_ARG;
}
switch (options->macAlgo) {
case ecHMAC_SHA256:
*digestSz = SHA256_DIGEST_SIZE;
break;
default:
return BAD_FUNC_ARG;
}
} else
return BAD_FUNC_ARG;
*keysLen = *encKeySz + *ivSz + *digestSz;
return 0;
}
/* ecc encrypt with shared secret run through kdf
options holds non default algos and inputs
msgSz should be the right size for encAlgo, i.e., already padded
return 0 on success */
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncOptions* opts)
{
int ret;
word32 blockSz;
word32 digestSz;
ecEncOptions options;
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
byte keys[ECC_BUFSIZE]; /* max size */
word32 sharedSz = sizeof(sharedSecret);
int keysLen;
int encKeySz;
int ivSz;
byte* encKey;
byte* encIv;
byte* macKey;
if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
outSz == NULL)
return BAD_FUNC_ARG;
if (opts)
options = *opts;
else {
ecc_encrypt_init_options(&options); /* defaults */
}
ret = ecc_get_key_sizes(&options, &encKeySz, &ivSz, &keysLen, &digestSz,
&blockSz);
if (ret != 0)
return ret;
if ( (msgSz%blockSz) != 0)
return BAD_FUNC_ARG;
if (*outSz < (msgSz + digestSz))
return BUFFER_E;
ret = ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz);
if (ret != 0)
return ret;
switch (options.kdfAlgo) {
case ecHKDF_SHA256 :
ret = HKDF(SHA256, sharedSecret, sharedSz, options.kdfSalt,
options.kdfSaltSz, options.kdfInfo,
options.kdfInfoSz, keys, keysLen);
if (ret != 0)
return ret;
break;
default:
return BAD_FUNC_ARG;
}
encKey = keys;
encIv = encKey + encKeySz;
macKey = encKey + encKeySz + ivSz;
switch (options.encAlgo) {
case ecAES_128_CBC:
{
Aes aes;
ret = AesSetKey(&aes, encKey,KEY_SIZE_128,encIv,AES_ENCRYPTION);
if (ret != 0)
return ret;
ret = AesCbcEncrypt(&aes, out, msg, msgSz);
if (ret != 0)
return ret;
}
break;
default:
return BAD_FUNC_ARG;
}
switch (options.macAlgo) {
case ecHMAC_SHA256:
{
Hmac hmac;
ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
if (ret != 0)
return ret;
HmacUpdate(&hmac, out, msgSz);
HmacUpdate(&hmac, options.macSalt, options.macSaltSz);
HmacFinal(&hmac, out+msgSz);
}
break;
default:
return BAD_FUNC_ARG;
}
*outSz = msgSz + digestSz;
return 0;
}
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncOptions* opts)
{
int ret;
word32 blockSz;
word32 digestSz;
ecEncOptions options;
byte sharedSecret[ECC_MAXSIZE]; /* 521 max size */
byte keys[ECC_BUFSIZE]; /* max size */
word32 sharedSz = sizeof(sharedSecret);
int keysLen;
int encKeySz;
int ivSz;
byte* encKey;
byte* encIv;
byte* macKey;
if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
outSz == NULL)
return BAD_FUNC_ARG;
if (opts)
options = *opts;
else {
ecc_encrypt_init_options(&options); /* defaults */
}
ret = ecc_get_key_sizes(&options, &encKeySz, &ivSz, &keysLen, &digestSz,
&blockSz);
if (ret != 0)
return ret;
if ( ((msgSz-digestSz) % blockSz) != 0)
return BAD_FUNC_ARG;
if (*outSz < (msgSz - digestSz))
return BUFFER_E;
ret = ecc_shared_secret(privKey, pubKey, sharedSecret, &sharedSz);
if (ret != 0)
return ret;
switch (options.kdfAlgo) {
case ecHKDF_SHA256 :
ret = HKDF(SHA256, sharedSecret, sharedSz, options.kdfSalt,
options.kdfSaltSz, options.kdfInfo,
options.kdfInfoSz, keys, keysLen);
if (ret != 0)
return ret;
break;
default:
return BAD_FUNC_ARG;
}
encKey = keys;
encIv = encKey + encKeySz;
macKey = encKey + encKeySz + ivSz;
switch (options.macAlgo) {
case ecHMAC_SHA256:
{
byte verify[SHA256_DIGEST_SIZE];
Hmac hmac;
ret = HmacSetKey(&hmac, SHA256, macKey, SHA256_DIGEST_SIZE);
if (ret != 0)
return ret;
HmacUpdate(&hmac, msg, msgSz-digestSz);
HmacUpdate(&hmac, options.macSalt, options.macSaltSz);
HmacFinal(&hmac, verify);
if (memcmp(verify, msg + msgSz - digestSz, digestSz) != 0) {
return -1;
}
}
break;
default:
return BAD_FUNC_ARG;
}
switch (options.encAlgo) {
case ecAES_128_CBC:
{
Aes aes;
ret = AesSetKey(&aes, encKey,KEY_SIZE_128,encIv,AES_DECRYPTION);
if (ret != 0)
return ret;
ret = AesCbcDecrypt(&aes, out, msg, msgSz-digestSz);
if (ret != 0)
return ret;
}
break;
default:
return BAD_FUNC_ARG;
}
*outSz = msgSz - digestSz;
return 0;
}
#endif /* HAVE_ECC_ENCRYPT */
#endif /* HAVE_ECC */

View File

@@ -158,6 +158,9 @@ int pkcs12_test(void);
int pbkdf2_test(void);
#ifdef HAVE_ECC
int ecc_test(void);
#ifdef HAVE_ECC_ENCRYPT
int ecc_encrypt_test(void);
#endif
#endif
#ifdef HAVE_BLAKE2
int blake2b_test(void);
@@ -434,6 +437,12 @@ void ctaocrypt_test(void* args)
err_sys("ECC test failed!\n", ret);
else
printf( "ECC test passed!\n");
#ifdef HAVE_ECC_ENCRYPT
if ( (ret = ecc_encrypt_test()) != 0)
err_sys("ECC Enc test failed!\n", ret);
else
printf( "ECC Enc test passed!\n");
#endif
#endif
#ifdef HAVE_LIBZ
@@ -3583,6 +3592,56 @@ int ecc_test(void)
return 0;
}
#ifdef HAVE_ECC_ENCRYPT
int ecc_encrypt_test(void)
{
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 = InitRng(&rng);
if (ret != 0)
return -3001;
ecc_init(&userA);
ecc_init(&userB);
ret = ecc_make_key(&rng, 32, &userA);
ret += ecc_make_key(&rng, 32, &userB);
if (ret != 0)
return -3002;
for (i = 0; i < 48; i++)
msg[i] = i;
/* send encrypted msg to B */
ret = ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL);
if (ret != 0)
return -3003;
/* decrypted msg to B */
ret = ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, NULL);
if (ret != 0)
return -3004;
if (memcmp(plain, msg, sizeof(msg)) != 0)
return -3005;
ecc_free(&userB);
ecc_free(&userA);
return 0;
}
#endif /* HAVE_ECC_ENCRYPT */
#endif /* HAVE_ECC */
#ifdef HAVE_LIBZ

View File

@@ -119,6 +119,53 @@ CYASSL_API
int ecc_sig_size(ecc_key* key);
/* ecc encrypt */
enum ecEncAlgo {
ecAES_128_CBC = 1, /* default */
ecAES_256_CBC = 2
};
enum ecKdfAlgo {
ecHKDF_SHA256 = 1, /* default */
ecHKDF_SHA1 = 2
};
enum ecMacAlgo {
ecHMAC_SHA256 = 1, /* default */
ecHMAC_SHA1 = 2
};
enum {
KEY_SIZE_128 = 16,
KEY_SIZE_256 = 32,
IV_SIZE_64 = 8
};
typedef struct ecEncOptions {
byte encAlgo; /* which encryption type */
byte kdfAlgo; /* which key derivation function type */
byte macAlgo; /* which mac function type */
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 */
} ecEncOptions;
CYASSL_API
void ecc_encrypt_init_options(ecEncOptions*); /* init and set to defaults */
CYASSL_API
void ecc_encrypt_free_options(ecEncOptions*); /* release/clear options */
CYASSL_API
int ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncOptions* options);
CYASSL_API
int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncOptions* options);
#ifdef __cplusplus
} /* extern "C" */
#endif