Files
GmSSL/crypto/ecies/ecies_lib.c
2019-08-13 16:56:23 +08:00

766 lines
20 KiB
C

/* ====================================================================
* Copyright (c) 2007 - 2017 The GmSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the GmSSL Project.
* (http://gmssl.org/)"
*
* 4. The name "GmSSL Project" must not be used to endorse or promote
* products derived from this software without prior written
* permission. For written permission, please contact
* guanzhi1980@gmail.com.
*
* 5. Products derived from this software may not be called "GmSSL"
* nor may "GmSSL" appear in their names without prior written
* permission of the GmSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the GmSSL Project
* (http://gmssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslconf.h>
#ifndef OPENSSL_NO_AES
# include <openssl/aes.h>
#endif
#include <openssl/hmac.h>
#ifndef OPENSSL_NO_CMAC
# include <openssl/cmac.h>
#endif
#include <openssl/rand.h>
#include <openssl/ecdh.h>
#include <openssl/kdf2.h>
#include <openssl/ecies.h>
#include "internal/o_str.h"
#include "ecies_lcl.h"
#define ECIES_ENC_RANDOM_IV 1
int ECIES_PARAMS_init_with_type(ECIES_PARAMS *params, int type)
{
if (!params) {
ECerr(EC_F_ECIES_PARAMS_INIT_WITH_TYPE, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
switch (type) {
#ifndef OPENSSL_NO_SHA
case NID_ecies_with_x9_63_sha1_xor_hmac:
params->kdf_nid = NID_x9_63_kdf;
params->kdf_md = EVP_sha1();
params->enc_nid = NID_xor_in_ecies;
params->mac_nid = NID_hmac_full_ecies;
params->hmac_md = EVP_sha1();
break;
# ifndef OPENSSL_NO_SHA256
case NID_ecies_with_x9_63_sha256_xor_hmac:
params->kdf_nid = NID_x9_63_kdf;
params->kdf_md = EVP_sha256();
params->enc_nid = NID_xor_in_ecies;
params->mac_nid = NID_hmac_full_ecies;
params->hmac_md = EVP_sha256();
break;
# endif
#endif
default:
ECerr(EC_F_ECIES_PARAMS_INIT_WITH_TYPE, EC_R_INVALID_ECIES_PARAMS);
return 0;
}
return 1;
}
int ECIES_PARAMS_init_with_recommended(ECIES_PARAMS *param)
{
if (!param) {
ECerr(EC_F_ECIES_PARAMS_INIT_WITH_RECOMMENDED,
ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
memset(param, 0, sizeof(*param));
#ifndef OPENSSL_NO_SHA256
param->kdf_nid = NID_x9_63_kdf;
param->kdf_md = EVP_sha256();
param->enc_nid = NID_xor_in_ecies;
param->mac_nid = NID_hmac_full_ecies;
param->hmac_md = EVP_sha256();
return 1;
#else
ECerr(EC_F_ECIES_PARAMS_INIT_WITH_RECOMMENDED,
EC_R_INVALID_ECIES_PARAMS);
return 0;
#endif
}
KDF_FUNC ECIES_PARAMS_get_kdf(const ECIES_PARAMS *param)
{
if (!param || !param->kdf_md) {
ECerr(EC_F_ECIES_PARAMS_GET_KDF, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
switch (param->kdf_nid) {
case NID_x9_63_kdf:
return KDF_get_x9_63(param->kdf_md);
case NID_nist_concatenation_kdf:
case NID_tls_kdf:
case NID_ikev2_kdf:
ECerr(EC_F_ECIES_PARAMS_GET_KDF, EC_R_NOT_IMPLEMENTED);
return NULL;
}
ECerr(EC_F_ECIES_PARAMS_GET_KDF, EC_R_INVALID_ECIES_PARAMETERS);
return NULL;
}
int ECIES_PARAMS_get_enc(const ECIES_PARAMS *param, size_t inlen,
const EVP_CIPHER **enc_cipher, size_t *enckeylen, size_t *ciphertextlen)
{
const EVP_CIPHER *cipher = NULL;
size_t keylen;
size_t outlen;
if (!param || !enc_cipher || !enckeylen || !ciphertextlen) {
ECerr(EC_F_ECIES_PARAMS_GET_ENC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
switch (param->enc_nid) {
case NID_xor_in_ecies:
cipher = NULL;
keylen = inlen;
break;
#ifndef OPENSSL_NO_AES
case NID_aes128_cbc_in_ecies:
cipher = EVP_aes_128_cbc();
break;
case NID_aes192_cbc_in_ecies:
cipher = EVP_aes_192_cbc();
break;
case NID_aes256_cbc_in_ecies:
cipher = EVP_aes_256_cbc();
break;
case NID_aes128_ctr_in_ecies:
cipher = EVP_aes_128_ctr();
break;
case NID_aes192_ctr_in_ecies:
cipher = EVP_aes_192_ctr();
break;
case NID_aes256_ctr_in_ecies:
cipher = EVP_aes_256_ctr();
break;
#endif
default:
ECerr(EC_F_ECIES_PARAMS_GET_ENC, EC_R_INVALID_ECIES_PARAMETERS);
return 0;
}
outlen = inlen;
if (cipher) {
int blocksize = EVP_CIPHER_block_size(cipher);
keylen = EVP_CIPHER_key_length(cipher);
if (ECIES_ENC_RANDOM_IV) {
outlen += blocksize;
}
if (EVP_CIPHER_mode(cipher) == EVP_CIPH_CBC_MODE) {
outlen += blocksize - inlen % blocksize;
}
}
*enc_cipher = cipher;
*enckeylen = keylen;
*ciphertextlen = outlen;
return 1;
}
int ECIES_PARAMS_get_mac(const ECIES_PARAMS *param,
const EVP_MD **hmac_md, const EVP_CIPHER **cmac_cipher,
unsigned int *mackeylen, unsigned int *maclen)
{
const EVP_CIPHER *cipher = NULL;
const EVP_MD *md = NULL;
unsigned int keylen;
unsigned int outlen;
if (!param || !hmac_md || !cmac_cipher || !mackeylen || !maclen) {
ECerr(EC_F_ECIES_PARAMS_GET_MAC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
switch (param->mac_nid) {
case NID_hmac_full_ecies:
if (!(md = param->hmac_md)) {
ECerr(EC_F_ECIES_PARAMS_GET_MAC,
EC_R_INVALID_ECIES_PARAMETERS);
return 0;
}
keylen = EVP_MD_size(md);
outlen = EVP_MD_size(md);
break;
case NID_hmac_half_ecies:
if (!(md = param->hmac_md)) {
ECerr(EC_F_ECIES_PARAMS_GET_MAC,
EC_R_INVALID_ECIES_PARAMETERS);
return 0;
}
keylen = EVP_MD_size(md);
outlen = EVP_MD_size(md)/2;
break;
#ifndef OPENSSL_NO_AES
case NID_cmac_aes128_ecies:
cipher = EVP_aes_128_ecb();
break;
case NID_cmac_aes192_ecies:
cipher = EVP_aes_192_ecb();
break;
case NID_cmac_aes256_ecies:
cipher = EVP_aes_256_ecb();
break;
#endif
default:
ECerr(EC_F_ECIES_PARAMS_GET_MAC,
EC_R_INVALID_ECIES_PARAMETERS);
return 0;
}
if (cipher) {
keylen = EVP_CIPHER_key_length(cipher);
outlen = EVP_CIPHER_block_size(cipher);
}
*hmac_md = md;
*cmac_cipher = cipher;
*mackeylen = keylen;
*maclen = outlen;
return 1;
}
int ECIES_CIPHERTEXT_VALUE_ciphertext_length(const ECIES_CIPHERTEXT_VALUE *a)
{
return ASN1_STRING_length(a->ciphertext);
}
ECIES_CIPHERTEXT_VALUE *ECIES_do_encrypt(const ECIES_PARAMS *param,
const unsigned char *in, size_t inlen, EC_KEY *ec_key)
{
int e = 1;
KDF_FUNC kdf_func;
const EVP_CIPHER *enc_cipher = NULL;
size_t enckeylen, ciphertextlen;
const EVP_MD *hmac_md = NULL;
const EVP_CIPHER *mac_cipher = NULL;
unsigned int mackeylen, maclen;
ECIES_CIPHERTEXT_VALUE *ret = NULL;
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
EC_KEY *ephem_key = NULL;
int point_form = POINT_CONVERSION_COMPRESSED;
unsigned char *sharekey = NULL;
unsigned int sharekeylen;
unsigned char *enckey, *mackey;
unsigned char mac[EVP_MAX_MD_SIZE];
size_t len;
if (!param || !in || !inlen || !ec_key || !group) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
/* parse parameters */
if (!(kdf_func = ECIES_PARAMS_get_kdf(param))) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
if (!ECIES_PARAMS_get_enc(param, inlen, &enc_cipher, &enckeylen, &ciphertextlen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
if (!ECIES_PARAMS_get_mac(param, &hmac_md, &mac_cipher, &mackeylen, &maclen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
/* malloc ciphertext value */
if (!(ret = ECIES_CIPHERTEXT_VALUE_new())) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
return 0;
}
/* generate ephem keypair */
if (!(ephem_key = EC_KEY_new())) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!EC_KEY_set_group(ephem_key, group)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_EC_LIB);
goto end;
}
if (!EC_KEY_generate_key(ephem_key)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_EC_LIB);
goto end;
}
/* output ephem_point */
len = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ephem_key),
point_form, NULL, 0, NULL);
if (!ASN1_OCTET_STRING_set(ret->ephem_point, NULL, len)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_ASN1_LIB);
goto end;
}
if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(ephem_key),
point_form, ret->ephem_point->data, len, NULL) <= 0) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_EC_LIB);
goto end;
}
/* ecdh to generate enckey and mackey */
sharekeylen = enckeylen + mackeylen;
if (!(sharekey = OPENSSL_malloc(sharekeylen))) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!ECDH_compute_key(sharekey, sharekeylen,
EC_KEY_get0_public_key(ec_key), ephem_key,
kdf_func)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_ECDH_FAILED);
goto end;
}
enckey = sharekey;
mackey = sharekey + enckeylen;
/* encrypt */
if (!ASN1_OCTET_STRING_set(ret->ciphertext, NULL, ciphertextlen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (enc_cipher) {
EVP_CIPHER_CTX *cipher_ctx = NULL;
unsigned char ivbuf[EVP_MAX_IV_LENGTH];
unsigned char *iv, *pout;
unsigned int ivlen, len;
ivlen = EVP_CIPHER_iv_length(enc_cipher);
if (ECIES_ENC_RANDOM_IV) {
iv = ret->ciphertext->data;
pout = ret->ciphertext->data + ivlen;
RAND_bytes(iv, ivlen);
} else {
iv = ivbuf;
pout = ret->ciphertext->data;
memset(iv, 0, ivlen);
}
if (!(cipher_ctx = EVP_CIPHER_CTX_new())) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!EVP_EncryptInit(cipher_ctx, enc_cipher, enckey, iv)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_ENCRYPT_FAILED);
EVP_CIPHER_CTX_free(cipher_ctx);
goto end;
}
if (!EVP_EncryptUpdate(cipher_ctx, pout, (int *)&len, in, inlen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_ENCRYPT_FAILED);
EVP_CIPHER_CTX_free(cipher_ctx);
goto end;
}
pout += len;
if (!EVP_EncryptFinal(cipher_ctx, pout, (int *)&len)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_ENCRYPT_FAILED);
goto end;
}
pout += len;
OPENSSL_assert(pout - ret->ciphertext->data == ciphertextlen);
} else {
int i;
for (i = 0; i < ret->ciphertext->length; i++) {
ret->ciphertext->data[i] = in[i] ^ enckey[i];
}
}
/* generate mac */
if (mac_cipher) {
CMAC_CTX *cmac_ctx;
if (!(cmac_ctx = CMAC_CTX_new())) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!CMAC_Init(cmac_ctx, mackey, mackeylen, mac_cipher, NULL)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_CMAC_INIT_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
if (!CMAC_Update(cmac_ctx, ret->ciphertext->data, ret->ciphertext->length)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_CMAC_UPDATE_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
len = sizeof(mac);
if (!CMAC_Final(cmac_ctx, mac, &len)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_CMAC_FINAL_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
OPENSSL_assert(len == maclen);
CMAC_CTX_free(cmac_ctx);
} else {
len = sizeof(mac);
if (!HMAC(param->hmac_md, mackey, mackeylen,
ret->ciphertext->data, ret->ciphertext->length,
mac, &maclen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, EC_R_HMAC_FAILURE);
goto end;
}
OPENSSL_assert(len == maclen || len/2 == maclen);
}
if (!ASN1_OCTET_STRING_set(ret->mactag, mac, maclen)) {
ECerr(EC_F_ECIES_DO_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
e = 0;
end:
EC_KEY_free(ephem_key);
OPENSSL_free(sharekey);
if (e && ret) {
ECIES_CIPHERTEXT_VALUE_free(ret);
ret = NULL;
}
return ret;
}
int ECIES_do_decrypt(const ECIES_PARAMS *param, const ECIES_CIPHERTEXT_VALUE *in,
unsigned char *out, size_t *outlen, EC_KEY *ec_key)
{
int ret = 0;
KDF_FUNC kdf_func;
const EVP_CIPHER *enc_cipher = NULL;
size_t enckeylen, ciphertextlen;
const EVP_MD *hmac_md = NULL;
const EVP_CIPHER *mac_cipher = NULL;
unsigned int mackeylen, maclen;
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
EC_POINT *ephem_point = NULL;
unsigned char *sharekey = NULL;
unsigned int sharekeylen;
unsigned char *enckey, *mackey;
unsigned char mac[EVP_MAX_MD_SIZE];
size_t len;
if (!param || !in || !outlen || !ec_key || !group) {
ECerr(EC_F_ECIES_DO_DECRYPT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (!out) {
*outlen = in->ciphertext->length;
return 1;
}
if (*outlen < in->ciphertext->length) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_BUFFER_TOO_SMALL);
return 0;
}
/* parse parameters */
if (!(kdf_func = ECIES_PARAMS_get_kdf(param))) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
if (!ECIES_PARAMS_get_enc(param, in->ciphertext->length,
&enc_cipher, &enckeylen, &ciphertextlen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
if (!ECIES_PARAMS_get_mac(param, &hmac_md, &mac_cipher, &mackeylen, &maclen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_PARAMETERS);
goto end;
}
/* parse ephem_point */
if (!in->ephem_point || !in->ephem_point->data || in->ephem_point->length <= 0) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
if (!(ephem_point = EC_POINT_new(group))) {
ECerr(EC_F_ECIES_DO_DECRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!EC_POINT_oct2point(group, ephem_point,
in->ephem_point->data, in->ephem_point->length, NULL)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
/* compute ecdh, get enckey and mackey */
sharekeylen = enckeylen + mackeylen;
if (!(sharekey = OPENSSL_malloc(sharekeylen))) {
ECerr(EC_F_ECIES_DO_DECRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!ECDH_compute_key(sharekey, sharekeylen,
ephem_point, ec_key, kdf_func)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_ECDH_FAILURE);
goto end;
}
enckey = sharekey;
mackey = sharekey + enckeylen;
/* generate and verify mac */
if (!in->mactag || !in->mactag->data) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
if (mac_cipher) {
CMAC_CTX *cmac_ctx;
if (!(cmac_ctx = CMAC_CTX_new())) {
ECerr(EC_F_ECIES_DO_DECRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!CMAC_Init(cmac_ctx, mackey, mackeylen, mac_cipher, NULL)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_CMAC_INIT_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
if (!CMAC_Update(cmac_ctx, in->ciphertext->data, in->ciphertext->length)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_CMAC_UPDATE_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
len = sizeof(mac);
if (!CMAC_Final(cmac_ctx, mac, &len)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_CMAC_FINAL_FAILURE);
CMAC_CTX_free(cmac_ctx);
goto end;
}
OPENSSL_assert(len == maclen);
CMAC_CTX_free(cmac_ctx);
} else {
unsigned int ulen;
ulen = sizeof(mac);
if (!HMAC(param->hmac_md, mackey, mackeylen,
in->ciphertext->data, in->ciphertext->length,
mac, &ulen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_GEN_MAC_FAILED);
goto end;
}
len = (size_t)ulen;
OPENSSL_assert(len == maclen || len/2 == maclen);
}
if (maclen != in->mactag->length) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_ECIES_VERIFY_MAC_FAILURE);
goto end;
}
if (OPENSSL_memcmp(in->mactag->data, mac, maclen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_ECIES_VERIFY_MAC_FAILURE);
goto end;
}
/* decrypt */
if (enc_cipher) {
EVP_CIPHER_CTX *cipher_ctx = NULL;
unsigned char ivbuf[EVP_MAX_IV_LENGTH];
unsigned char *iv, *pin, *pout;
unsigned int ivlen, inlen;
int ilen;
/* prepare iv */
ivlen = EVP_CIPHER_iv_length(enc_cipher);
if (ECIES_ENC_RANDOM_IV) {
iv = in->ciphertext->data;
pin = in->ciphertext->data + ivlen;
if (in->ciphertext->length < ivlen) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
inlen = in->ciphertext->length - ivlen;
} else {
/* use fixed all-zero iv */
memset(ivbuf, 0, ivlen);
iv = ivbuf;
pin = in->ciphertext->data;
if (in->ciphertext->length <= 0) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
inlen = in->ciphertext->length;
}
/* decrypt */
if (!(cipher_ctx = EVP_CIPHER_CTX_new())) {
ECerr(EC_F_ECIES_DO_DECRYPT, ERR_R_MALLOC_FAILURE);
goto end;
}
if (!EVP_DecryptInit(cipher_ctx, enc_cipher, enckey, iv)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_ECIES_DECRYPT_INIT_FAILURE);
EVP_CIPHER_CTX_free(cipher_ctx);
goto end;
}
pout = out;
ilen = (int)*outlen; //FIXME: do we need to check it?
if (!EVP_DecryptUpdate(cipher_ctx, pout, &ilen, pin, inlen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_DECRYPT_FAILED);
EVP_CIPHER_CTX_free(cipher_ctx);
goto end;
}
pout += ilen;
if (!EVP_DecryptFinal(cipher_ctx, pout, &ilen)) {
ECerr(EC_F_ECIES_DO_DECRYPT, EC_R_DECRYPT_FAILED);
EVP_CIPHER_CTX_free(cipher_ctx);
goto end;
}
pout += ilen;
EVP_CIPHER_CTX_free(cipher_ctx);
*outlen = pout - out;
} else {
unsigned int i;
for (i = 0; i < in->ciphertext->length; i++) {
out[i] = in->ciphertext->data[i] ^ enckey[i];
}
*outlen = in->ciphertext->length;
}
ret = 1;
end:
OPENSSL_free(sharekey);
EC_POINT_free(ephem_point);
return ret;
}
int ECIES_encrypt(int type, const unsigned char *in, size_t inlen,
unsigned char *out, size_t *outlen, EC_KEY *ec_key)
{
int ret = 0;
ECIES_PARAMS param;
ECIES_CIPHERTEXT_VALUE *cv = NULL;
unsigned char *p = out;
int len;
if (!ECIES_PARAMS_init_with_type(&param, type)) {
ECerr(EC_F_ECIES_ENCRYPT, EC_R_INVALID_ENC_PARAM);
return 0;
}
RAND_seed(in, inlen);
if (!(cv = ECIES_do_encrypt(&param, in, inlen, ec_key))) {
ECerr(EC_F_ECIES_ENCRYPT, EC_R_ENCRYPT_FAILED);
return 0;
}
if ((len = i2d_ECIES_CIPHERTEXT_VALUE(cv, NULL)) <= 0) {
ECerr(EC_F_ECIES_ENCRYPT, EC_R_ENCRYPT_FAILED);
goto end;
}
if (!out) {
*outlen = (size_t)len;
ret = 1;
goto end;
} else if (*outlen < len) {
ECerr(EC_F_ECIES_ENCRYPT, EC_R_BUFFER_TOO_SMALL);
*outlen = (size_t)len;
goto end;
}
if ((len = i2d_ECIES_CIPHERTEXT_VALUE(cv, &p)) <= 0) {
ECerr(EC_F_ECIES_ENCRYPT, EC_R_ENCRYPT_FAILED);
goto end;
}
*outlen = (size_t)len;
ret = 1;
end:
ECIES_CIPHERTEXT_VALUE_free(cv);
return ret;
}
int ECIES_decrypt(int type, const unsigned char *in, size_t inlen,
unsigned char *out, size_t *outlen, EC_KEY *ec_key)
{
int ret = 0;
ECIES_PARAMS param;
ECIES_CIPHERTEXT_VALUE *cv = NULL;
if (!in) {
ECerr(EC_F_ECIES_DECRYPT, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (inlen <= 0 || inlen > INT_MAX) {
ECerr(EC_F_ECIES_DECRYPT, EC_R_INVALID_INPUT_LENGTH);
return 0;
}
if (!ECIES_PARAMS_init_with_type(&param, type)) {
ECerr(EC_F_ECIES_DECRYPT, EC_R_INVALID_ENC_PARAM);
return 0;
}
if (!(cv = d2i_ECIES_CIPHERTEXT_VALUE(NULL, &in, (long)inlen))) {
ECerr(EC_F_ECIES_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
return 0;
}
if (inlen != i2d_ECIES_CIPHERTEXT_VALUE(cv, NULL)) {
ECerr(EC_F_ECIES_DECRYPT, EC_R_INVALID_ECIES_CIPHERTEXT);
goto end;
}
if (!ECIES_do_decrypt(&param, cv, out, outlen, ec_key)) {
ECerr(EC_F_ECIES_DECRYPT, EC_R_ENCRYPT_FAILURE);
goto end;
}
ret = 1;
end:
ECIES_CIPHERTEXT_VALUE_free(cv);
return ret;
}